为什么将长二维列表转换为 numpy 数组这么慢?
回答问题 我有一长串 xy 坐标,并想将其转换为 numpy 数组。 >>> import numpy as np >>> xy = np.random.rand(1000000, 2).tolist() 显而易见的方法是: >>> a = np.array(xy) # Very slow... 但是,上面的代码速度慢得不合理。有趣的是,首先转置长列表,将其转换为 numpy 数组,然后转回会快得
·
回答问题
我有一长串 xy 坐标,并想将其转换为 numpy 数组。
>>> import numpy as np
>>> xy = np.random.rand(1000000, 2).tolist()
显而易见的方法是:
>>> a = np.array(xy) # Very slow...
但是,上面的代码速度慢得不合理。有趣的是,首先转置长列表,将其转换为 numpy 数组,然后转回会快得多(在我的笔记本电脑上是 20 倍)。
>>> def longlist2array(longlist):
... wide = [[row[c] for row in longlist] for c in range(len(longlist[0]))]
... return np.array(wide).T
>>> a = longlist2array(xy) # 20x faster!
这是numpy的错误吗?
编辑:
这是一个动态生成的点列表(带有 xy 坐标),因此我认为当前的表示是最自然的,而不是预先分配一个数组并在必要时扩大它,或者为 x 和 y 维护两个 1D 列表。
考虑到我们在两个方向上遍历 python 列表,为什么循环第二个索引比第一个索引快?
编辑2:
根据@tiago 的回答和这个问题,我发现以下代码的速度是原始版本的两倍:
>>> from itertools import chain
>>> def longlist2array(longlist):
... flat = np.fromiter(chain.from_iterable(longlist), np.array(longlist[0][0]).dtype, -1) # Without intermediate list:)
... return flat.reshape((len(longlist), -1))
Answers
在 Cython 中实现这一点,无需额外检查以确定维度等,几乎消除了您所看到的时间差异。这是我用来验证的.pyx
文件。
from numpy cimport ndarray as ar
import numpy as np
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def toarr(xy):
cdef int i, j, h=len(xy), w=len(xy[0])
cdef ar[double,ndim=2] new = np.empty((h,w))
for i in xrange(h):
for j in xrange(w):
new[i,j] = xy[i][j]
return new
我假设额外的时间用于检查每个子列表的长度和内容,以确定所需数组的数据类型、维度和大小。当只有两个子列表时,它只需要检查两个长度来确定数组中的列数,而不是检查其中的 1000000 个。
更多推荐
已为社区贡献126473条内容
所有评论(0)