Преобразование типа места в массиве NumPy
Учитывая массив NumPy int32
, как его преобразовать в float32
на месте? Итак, в основном, я хотел бы сделать
a = a.astype(numpy.float32)
без копирования массива. Он большой.
Причиной для этого является то, что у меня есть два алгоритма для вычисления a
. Один из них возвращает массив из int32
, другой возвращает массив float32
(и это присуще двум различным алгоритмам). Все дальнейшие вычисления предполагают, что a
является массивом float32
.
В настоящее время я выполняю преобразование в функции C, вызванной через ctypes
. Есть ли способ сделать это в Python?
Ответы
Ответ 1
Вы можете сделать вид с другим dtype, а затем скопировать на место в виде:
import numpy as np
x = np.arange(10, dtype='int32')
y = x.view('float32')
y[:] = x
print(y)
дает
array([ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32)
Чтобы показать, что преобразование было на месте, обратите внимание, что копирование из x
в y
изменено x
:
print(x)
печатает
array([ 0, 1065353216, 1073741824, 1077936128, 1082130432,
1084227584, 1086324736, 1088421888, 1090519040, 1091567616])
Ответ 2
Обновление: эта функция позволяет избежать копирования, если это возможно, поэтому это неправильный ответ на этот вопрос. Ответ @unutbu правильный.
a = a.astype(numpy.float32, copy=False)
numpy astype имеет флаг копирования. Почему мы не должны использовать его?
Ответ 3
Вы можете изменить тип массива без преобразования следующим образом:
a.dtype = numpy.float32
но сначала вам нужно изменить все целые числа на то, что будет интерпретироваться как соответствующее поплавок. Очень медленный способ сделать это - использовать модуль python struct
следующим образом:
def toi(i):
return struct.unpack('i',struct.pack('f',float(i)))[0]
... применяется к каждому члену вашего массива.
Но, возможно, более быстрым способом было бы использовать инструменты numpy ctypeslib (с которыми я не знаком)
- изменить -
Так как ctypeslib, похоже, не работает, тогда я бы продолжил преобразование с помощью типичного метода numpy.astype
, но продолжаю размеры блоков, которые находятся в пределах вашей памяти:
a[0:10000] = a[0:10000].astype('float32').view('int32')
... затем измените dtype, когда закончите.
Вот функция, которая выполняет задачу для любых совместимых типов dtypes (работает только для dtypes с элементами одинакового размера) и обрабатывает массивы произвольной формы с пользовательским контролем над размером блока:
import numpy
def astype_inplace(a, dtype, blocksize=10000):
oldtype = a.dtype
newtype = numpy.dtype(dtype)
assert oldtype.itemsize is newtype.itemsize
for idx in xrange(0, a.size, blocksize):
a.flat[idx:idx + blocksize] = \
a.flat[idx:idx + blocksize].astype(newtype).view(oldtype)
a.dtype = newtype
a = numpy.random.randint(100,size=100).reshape((10,10))
print a
astype_inplace(a, 'float32')
print a
Ответ 4
a = np.subtract(a, 0., dtype=np.float32)
Ответ 5
Используйте это:
In [105]: a
Out[105]:
array([[15, 30, 88, 31, 33],
[53, 38, 54, 47, 56],
[67, 2, 74, 10, 16],
[86, 33, 15, 51, 32],
[32, 47, 76, 15, 81]], dtype=int32)
In [106]: float32(a)
Out[106]:
array([[ 15., 30., 88., 31., 33.],
[ 53., 38., 54., 47., 56.],
[ 67., 2., 74., 10., 16.],
[ 86., 33., 15., 51., 32.],
[ 32., 47., 76., 15., 81.]], dtype=float32)