将 numpy 数组转换为 C 连续顺序的最便宜方法



下面生成一个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))似乎是优化它的唯一合理方法。

最新更新