Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

python

numpy

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?

like image 923
Rob Smallshire Avatar asked Oct 10 '11 15:10

Rob Smallshire


1 Answers

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;

like image 92
pv. Avatar answered Nov 02 '22 22:11

pv.