Rob Smallshire
Rob Smallshire

Reputation: 1508

How can I efficiently transform a numpy.int8 array in-place to a value-shifted numpy.uint8 array?

I have a large numpy array of signed bytes (dtype int8). It contains values in the full range -128 to +127. I'd like to convert the efficiently to an array of unsigned bytes (dtype uint8) by adding 128 to each element, such that -128 → 0, 0 → 128, +127 → 255, etc. so of course the results still fit into an unsigned byte.

Simple elementwise addition given the correct numerical result, but creates a result array using twice the memory (dtype int16) in addition to the source array, even though only the low bytes of the result elements are needed.

>>> import numpy
>>> a = numpy.array( [-128, -1, 0, 1, 127 ], dtype=numpy.int8)
>>> b = a + 128
>>> b
array([  0, 127, 128, 129, 255], dtype=int16)

Is there a way to control the dtype of the result array to be uint8?

The alternative approach of modifying the values in-place and "casting" the data to a new type, like this:

>>> for i in xrange(0, 5):
...     if a[i] < 0:
...         a[i] -= 128
...     elif a[i] >= 0:
...         a[i] += 128
...
>>> a
array([   0,  127, -128, -127,   -1], dtype=int8)
>>> a.view(dtype=numpy.uint8)
array([  0, 127, 128, 129, 255], dtype=uint8)

is much more space efficient but very costly in time for large arrays with the transformation in Python.

How can I do this transformation in-place and quickly?

Upvotes: 9

Views: 15442

Answers (2)

pv.
pv.

Reputation: 35145

import numpy as np
a = np.array([-128, -1, 0, 1, 127], dtype=np.int8)
a = a.view(np.uint8)
a += 128
print a
# -> array([  0, 127, 128, 129, 255], dtype=uint8)

This creates no copies, and all operations are in-place.

EDIT: safer to cast first to uint --- unsigned wrap-around is defined. EDIT2: s/numpy/np/g;

Upvotes: 18

NPE
NPE

Reputation: 500733

In [18]: a = numpy.array( [-128, -1, 0, 1, 127 ], dtype=numpy.int8)
In [19]: z = a.view(dtype=numpy.uint8)

In [20]: z += 128

In [21]: z
Out[21]: array([  0, 127, 128, 129, 255], dtype=uint8)

I hope I haven't misunderstood the requirements.

Upvotes: 1

Related Questions