我有一个generator
,它产生了一些可变的但已知大小的小的一维NumPy数组。出于以下问题的目的,可以通过以下代码模仿我的设置:
import numpy as np
n = 1000
sizes = np.random.randint(1,10,n)
def generator():
for size in sizes:
yield np.random.random(size)
我反复需要将生成器产生的数组连接成一个大的一维数组,大致如下:
runs = 1000
output = np.empty(sum(sizes))
further_preparations(sizes)
for _ in range(runs):
my_concatenate(generator(),sizes,output)
我希望尽可能有效地做到这一点(无需使用C API,Cython或类似软件)。
以下方法是按照timeit
可以立即使用的方式编写的,例如:
import timeit
print(timeit.timeit(with_hstack,number=runs))
供参考:仅迭代生成器(for _ in generator(): pass
)需2.6 s。另外,将输出转换为列表(list(generator())
)需要2.9 s。在下面,我不减去这些时间:
np.hstack
(5.6秒):
def with_hstack():
np.hstack(generator())
np.concatenate
(3.1秒):
def with_concatenate():
np.concatenate(list(generator()),out=output)
带索引的循环(4.5秒):
def with_loop():
i = 0
for array in generator():
j = i + array.size
output[i:j] = array
i = j
阵列视图列表(3.7秒):
steps = np.hstack((0,np.cumsum(sizes)))
views = [ output[i:j] for i,j in zip(steps,steps[1:]) ]
def with_views():
for view,array in zip(views,generator()):
np.copyto(view,array)
上述方法的缺点之间没有完全重叠的部分,这表明可能有更好的解决方案。例如,以上数据表明,避免使用concatenate
进行列表转换可以节省大约0.3 s。有没有更好的解决方案?