NumPy数组的就地类型转换

Sve*_*ach 124 python numpy

给定NumPy数组int32,如何将其转换为float32 适当的位置?所以基本上,我想做

a = a.astype(numpy.float32)
Run Code Online (Sandbox Code Playgroud)

没有复制数组.它很大.

这样做的原因是我有两种计算算法a.其中一个返回一个数组int32,另一个返回一个数组float32(这是两个不同算法所固有的).所有进一步的计算都假定它a是一个数组float32.

目前我在一个名为via的C函数中进行转换ctypes.有没有办法在Python中执行此操作?

Vik*_*kas 155

更新:此功能仅在可能的情况下避免复制,因此这不是此问题的正确答案.unutbu的答案是正确的.


a = a.astype(numpy.float32, copy=False)
Run Code Online (Sandbox Code Playgroud)

numpy astype有一个复制标志.我们为什么不用它呢?

  • 在NumPy版本中支持此参数后,我们当然可以使用它,但目前它仅在开发分支中可用.当我问这个问题时,它根本不存在. (14认同)
  • 复制标志仅表示如果可以在没有副本的情况下完成更改,则无需复制即可完成.然而,它的类型不同,它仍将始终复制. (14认同)
  • @SvenMarnach现在支持它,至少在我的版本(1.7.1)中. (2认同)

unu*_*tbu 106

您可以使用不同的dtype创建视图,然后就地复制到视图中:

import numpy as np
x = np.arange(10, dtype='int32')
y = x.view('float32')
y[:] = x

print(y)
Run Code Online (Sandbox Code Playgroud)

产量

array([ 0.,  1.,  2.,  3.,  4.,  5.,  6.,  7.,  8.,  9.], dtype=float32)
Run Code Online (Sandbox Code Playgroud)

要显示转换是就地的,请注意 复制xy更改x:

print(x)
Run Code Online (Sandbox Code Playgroud)

版画

array([         0, 1065353216, 1073741824, 1077936128, 1082130432,
       1084227584, 1086324736, 1088421888, 1090519040, 1091567616])
Run Code Online (Sandbox Code Playgroud)

  • 请注意那些想要在不同字节大小的dtype(例如32到16位)之间进行转换的人(比如我):此方法失败,因为y.size <> x.size.逻辑一旦你想到它:-( (25认同)
  • @BasSwinckels:这是预期的.指定`y [:] = x`时会发生转换. (3认同)
  • 这种就地更改可能会节省内存使用,但它比简单的“x.astype(float)”转换慢。我不会推荐它,除非你的脚本接近 MemoryError。 (2认同)

Pau*_*aul 14

您可以更改数组类型而不像这样转换:

a.dtype = numpy.float32
Run Code Online (Sandbox Code Playgroud)

但首先你必须将所有整数更改为将被解释为相应浮点数的东西.一个非常慢的方法是使用这样的python struct模块:

def toi(i):
    return struct.unpack('i',struct.pack('f',float(i)))[0]
Run Code Online (Sandbox Code Playgroud)

...应用于数组的每个成员.

但也许更快的方法是利用numpy的ctypeslib工具(我不熟悉)

- 编辑 -

由于ctypeslib似乎不起作用,那么我将继续使用典型numpy.astype方法进行转换,但继续处理内存限制内的块大小:

a[0:10000] = a[0:10000].astype('float32').view('int32')
Run Code Online (Sandbox Code Playgroud)

...然后在完成后更改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
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的回答。老实说,我认为这对于**大**数组不是很有用——它太慢了。将数组的数据重新解释为不同的类型很容易——例如通过调用“a.view(numpy.float32)”。困难的部分实际上是转换数据。`numpy.ctypeslib` 仅有助于重新解释数据,而无助于实际转换数据。 (2认同)