下面生成一个C连续的numpy数组:
import numpy
a = numpy.ones((1024,1024,5))
现在,如果我切片,结果可能不再相同。例如:
bn = a[:, :, n]
n
从 0 到 4。我的问题是我需要bn
是 C 连续的,我需要为许多实例执行此操作。我只需要每个bn
一次,并且想避免这样做
bn = bn.copy(order='C')
我也不想重写我的代码,这样
a = numpy.ones((5,1024,1024))
有没有比复制更快、更便宜的方法来获得bn
?
背景:
我想对每个a
的每个切片进行哈希处理,使用
import hashlib
hashlib.sha1(a[:, :, n]).hexdigest()
不幸的是,这将引发ValueError
,抱怨订单。因此,如果有另一种快速方法可以获取我想要的哈希值,我也会使用它。
numpy 与 C 接口时的标准操作。看看 numpy.ascontiguousarray
x=numpy.ascontiguousarray(x)
是处理它的正确方法。
如果你需要 fortran order,请使用 numpy.asfortranarray。
如前所述,如有必要,该函数将复制。所以没有办法绕过它。您可以在操作前尝试滚动轴,使短轴是第一个轴。这为您提供了阵列的视图
In [2]: A=np.random.rand(1024,1024,5)
In [3]: B=np.rollaxis(A,2)
In [4]: B.shape
Out[4]: (5, 1024, 1024)
In [5]: B.flags
Out[5]:
C_CONTIGUOUS : False
F_CONTIGUOUS : False
OWNDATA : False
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
In [6]: A.flags
Out[6]:
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
所以滚动轴也不能解决这个问题。
就目前而言,任何将切片强制bn
C 连续顺序的尝试都将创建一个副本。
如果您不想更改开始时的形状(并且不需要按 C 顺序a
本身),一种可能的解决方案是从 Fortran 顺序的数组a
开始:
>>> a = numpy.ones((1024, 1024, 5), order='f')
然后,切片也是 F 连续的:
>>> bn = a[:, :, 0]
>>> bn.flags
C_CONTIGUOUS : False
F_CONTIGUOUS : True
OWNDATA : False
...
这意味着切片bn
的转置将按 C 顺序排列,并且转置不会创建副本:
>>> bn.T.flags
C_CONTIGUOUS : True
F_CONTIGUOUS : False
OWNDATA : False
...
然后,您可以对切片进行哈希处理:
>>> hashlib.sha1(bn.T).hexdigest()
'01dfa447dafe16b9a2972ce05c79410e6a96840e'
要强制 numpy 数组x
是 C 连续的,而不在开始时已经这样做时制作不必要的副本,您应该使用,
x = numpy.asarray(x, order='C')
请注意,如果此数组不是 C 连续的,则在效率方面可能与 x.copy(order='C')
相似。我认为没有办法解决它。除了将数据复制到新位置之外,您无法重新组织内存中数组的对齐方式。
重写代码,使其首先使用切片索引,因为numpy.ones((5,1024,1024))
似乎是优化它的唯一合理方法。