Преобразование типов на месте массива NumPy - PullRequest
120 голосов
/ 08 декабря 2010

Учитывая массив NumPy int32, как мне преобразовать его в float32 вместо ?В общем, я хотел бы сделать

a = a.astype(numpy.float32)

без копирования массива.Он большой.

Причина для этого в том, что у меня есть два алгоритма для вычисления a.Один из них возвращает массив int32, другой возвращает массив float32 (и это присуще двум различным алгоритмам).Все дальнейшие вычисления предполагают, что a является массивом float32.

В настоящее время я выполняю преобразование в функцию C, вызываемую через ctypes.Есть ли способ сделать это в Python?

Ответы [ 5 ]

154 голосов
/ 16 мая 2012

Обновление: эта функция избегает копирования, только если это возможно, следовательно, это не правильный ответ на этот вопрос. правильный ответ unutbu правильный.


a = a.astype(numpy.float32, copy=False)

numpy astype имеет флаг копирования. Почему бы нам не использовать его?

101 голосов
/ 09 декабря 2010

Вы можете создать представление с другим типом 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])
14 голосов
/ 08 декабря 2010

Вы можете изменить тип массива без преобразования следующим образом:

a.dtype = numpy.float32

но сначала вы должны изменить все целые числа на что-то, что будет интерпретироваться как соответствующее число с плавающей запятой. Очень медленный способ сделать это - использовать модуль Python struct, например:

def toi(i):
    return struct.unpack('i',struct.pack('f',float(i)))[0]

... применяется к каждому члену вашего массива.

Но, возможно, более быстрый способ - использовать инструменты ctypeslib от numpy (с которыми я не знаком)

- редактировать -

Поскольку 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
0 голосов
/ 17 ноября 2017

a = np.subtract(a, 0., dtype=np.float32)

0 голосов
/ 19 февраля 2015

Используйте это:

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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...