python - Fortran 有序(列优先)numpy 结构化数组可能吗?

标签 python arrays numpy recarray structured-array

我正在寻找一种更有效地分配 numpy 结构化数组列的方法。

例子:

my_col = fn_returning_1D_array(...)

在我的机器上执行速度比对结构化数组的列执行相同的分配快两倍以上:

test = np.ndarray(shape=(int(8e6),), dtype=dtype([('column1', 'S10'), ...more columns...]))
test['column1'] = fn_returning_1D_array(...)

我尝试使用 Fortran 顺序创建 test 但它没有帮助。据推测,这些字段在内存中保持交错。

有人知道吗?如果可以的话,我愿意使用低级 numpy 接口(interface)和 cython。


编辑 1:回应 hpaulj 的回答

仅当后者以行优先顺序创建时,recarray 列分配和“正常”数组列分配的明显等价性才会产生。对于列优先排序,这两个分配远非等效:

行优先

In [1]: import numpy as np

In [2]: M,N=int(1e7),10

In [4]: A1=np.zeros((M,N),'f')

In [9]: dt=np.dtype(','.join(['f' for _ in range(N)]))

In [10]: A2=np.zeros((M,),dtype=dt)

In [11]: X=np.arange(M+0.0)

In [13]: %timeit for n in range(N):A1[:,n]=X
1 loops, best of 3: 2.36 s per loop

In [15]: %timeit for n in dt.names: A2[n]=X
1 loops, best of 3: 2.36 s per loop

In [16]: %timeit A1[:,:]=X[:,None]
1 loops, best of 3: 334 ms per loop

In [8]: A1.flags
Out[8]:
  C_CONTIGUOUS : True
  F_CONTIGUOUS : False
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

专栏主要

In [1]: import numpy as np

In [2]: M,N=int(1e7),10

In [3]: A1=np.zeros((M,N),'f', 'F')

In [4]: dt=np.dtype(','.join(['f' for _ in range(N)]))

In [5]: A2=np.zeros((M,),dtype=dt)

In [6]: X=np.arange(M+0.0)

In [8]: %timeit for n in range(N):A1[:,n]=X
1 loops, best of 3: 374 ms per loop

In [9]: %timeit for n in dt.names: A2[n]=X
1 loops, best of 3: 2.43 s per loop

In [10]: %timeit A1[:,:]=X[:,None]
1 loops, best of 3: 380 ms per loop

In [11]: A1.flags
Out[11]:
  C_CONTIGUOUS : False
  F_CONTIGUOUS : True
  OWNDATA : True
  WRITEABLE : True
  ALIGNED : True
  UPDATEIFCOPY : False

请注意,对于列优先排序,两个缓冲区不再相同:

In [6]: A3=np.zeros_like(A2)

In [7]: A3.data = A1.data

In [20]: A2[0]
Out[20]: (0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0)

In [21]: A2[1]
Out[21]: (1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0)

In [16]: A3[0]
Out[16]: (0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)

In [17]: A3[1]
Out[17]: (10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0, 18.0, 19.0)

最佳答案

这些不是等效的操作。一个只是生成一个数组(并将其分配给一个变量,一个小 Action )。另一个生成数组并填充结构化数组的列。

my_col = fn_returning_1D_array(...)
test['column1'] = fn_returning_1D_array(...)

我认为更公平的比较是填充二维数组的列。

In [38]: M,N=1000,10
In [39]: A1=np.zeros((M,N),'f')   # 2D array
In [40]: dt=np.dtype(','.join(['f' for _ in range(N)]))
In [41]: A2=np.zeros((M,),dtype=dt)   # structured array
In [42]: X=np.arange(M+0.0)

In [43]: A1[:,0]=X   # fill a column
In [44]: A2['f0']=X   # fill a field

In [45]: timeit for n in range(N):A1[:,n]=X
10000 loops, best of 3: 65.3 µs per loop

In [46]: timeit for n in dt.names: A2[n]=X
10000 loops, best of 3: 40.6 µs per loop

我有点惊讶填充结构化数组的速度更快。

当然,填充二维数组的快速方法是使用广播:

In [50]: timeit A1[:,:]=X[:,None]
10000 loops, best of 3: 29.2 µs per loop

但是填充字段的改进并不是那么大。

我没有发现逐字段填充结构化数组有什么明显的错误。它必须比生成元组列表来填充整个数组更快。

我相信 A1A2 具有相同的数据缓冲区。例如,如果我制作 A2 的零副本,我可以用 A1 的 替换它的数据缓冲区,并得到一个有效的结构化数组

In [64]: A3=np.zeros_like(A2)
In [65]: A3.data=A1.data

因此,填充结构化数组的更快方法是进行最快的二维填充,然后是此data 赋值。

但在一般情况下,挑战在于创建兼容的二维数组。当所有字段数据类型都相同时,这很容易。使用混合数据类型,您必须在字节级别工作。有一些高级的 dtype 规范(带有偏移量等)可以促进这种映射。


现在您已将焦点转移到 Fortran 顺序。在二维数组的情况下确实有帮助。但这样做会以面向行的操作为代价。

In [89]: A1=np.zeros((M,N),'f',order='F')

In [90]: timeit A1[:,:]=X[:,None]
100000 loops, best of 3: 18.2 µs per loop

您没有提到的一件事是您打算如何使用这个数组,至少在最后一次重写问题之前没有提到。如果它只是一个按名称存储多个数组的地方,您可以使用直接的 Python 字典:

In [96]: timeit D={name:X.copy() for name in dt.names}
10000 loops, best of 3: 25.2 µs per loop

尽管这确实是对 X.copy() 的时间测试。

无论如何,在处理数据类型时,没有任何等同于 Fortran 顺序的方法。 reshapeswapaxesstrides、广播等数组操作都没有跨越“dtype”边界。

关于python - Fortran 有序(列优先)numpy 结构化数组可能吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29719324/

相关文章:

python 如何根据正则表达式拆分列表并对其进行排序

Python 套接字发送缓冲区与。强度

java - 如何使用 GSON 反序列化无 key 数组?

java - 从文件中读取,分割行并存储在数组中JAVA

java - token 语法错误 ";"

python - 减少 ndarray 中的一维

python - 如何返回该数组的最小索引?

python - 在其他 numpy 数组中查找 numpy 数组

python - 循环运行 label_image.py

python - 在 countvectorizer() 中找不到 get_feature_names