我有一长串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的答案和this question,我发现以下代码的速度是原始版本的两倍:
>>> 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))
答案 0 :(得分:5)
在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个。
答案 1 :(得分:3)
这是因为列表中变化最快的索引是最后一个,因此np.array()
必须遍历数组很多次,因为第一个索引要大得多。如果您的列表已转置,则np.array()
会比您的longlist2array
更快:
In [65]: import numpy as np
In [66]: xy = np.random.rand(10000, 2).tolist()
In [67]: %timeit longlist2array(xy)
100 loops, best of 3: 3.38 ms per loop
In [68]: %timeit np.array(xy)
10 loops, best of 3: 55.8 ms per loop
In [69]: xy = np.random.rand(2, 10000).tolist()
In [70]: %timeit longlist2array(xy)
10 loops, best of 3: 59.8 ms per loop
In [71]: %timeit np.array(xy)
1000 loops, best of 3: 1.96 ms per loop
您的问题没有神奇的解决方案。这就是Python将您的列表存储在内存中的方式。你真的需要一个有这种形状的清单吗?你能逆转吗? (你真的需要一个清单,因为你正在转变为numpy吗?)
如果您必须转换列表,此功能比longlist2array
:
from itertools import chain
def convertlist(longlist)
tmp = list(chain.from_iterable(longlist))
return np.array(tmp).reshape((len(longlist), len(longlist[0])))
答案 2 :(得分:3)
如果您有熊猫,可以使用pandas.lib.to_object_array()
,这是最快的方法:
import numpy as np
import pandas as pd
a = np.random.rand(100000, 2)
b = a.tolist()
%timeit np.array(b, dtype=float, ndmin=2)
%timeit np.array(b, dtype=object).astype(float)
%timeit np.array(zip(*b)).T
%timeit pd.lib.to_object_array(b).astype(float)
输出:
1 loops, best of 3: 462 ms per loop
1 loops, best of 3: 192 ms per loop
10 loops, best of 3: 39.9 ms per loop
100 loops, best of 3: 13.7 ms per loop