什么是迭代numpy数组的最快方法

piR*_*red 9 python numpy python-itertools pandas

我注意到"直接"迭代numpy数组与通过tolist方法迭代之间有一个有意义的区别.见下面的时间:

直接
[i for i in np.arange(10000000)]
通过tolist
[i for i in np.arange(10000000).tolist()]

在此输入图像描述


考虑到我发现了一种更快的方法.我想问一下还有什么可以让它变得更快?

什么是迭代numpy数组的最快方法?

Jam*_*mes 8

这实际上并不奇怪.让我们一次从最慢的方式开始检查方法.

[i for i in np.arange(10000000)]
Run Code Online (Sandbox Code Playgroud)

此方法要求python进入numpy数组(存储在C内存作用域中),一次一个元素,在内存中分配Python对象,并在列表中创建指向该对象的指针.每次在C后端存储的numpy数组之间进行管道处理并将其拉入纯python时,都会产生开销.这种方法增加了10,000,000次.

下一个:

[i for i in np.arange(10000000).tolist()]
Run Code Online (Sandbox Code Playgroud)

在这种情况下,using .tolist()对numpy C后端进行一次调用,并将一次性中的所有元素分配给一个列表.然后,您使用python迭代该列表.

最后:

list(np.arange(10000000))
Run Code Online (Sandbox Code Playgroud)

这基本上与上面的内容相同,但它创建了numpy的本机类型对象列表(例如np.int64).使用list(np.arange(10000000))np.arange(10000000).tolist()应该是大致相同的时间.


因此,就迭代而言,使用的主要优点numpy是您不需要迭代.在阵列上以矢量化方式应用操作.迭代只会减慢速度.如果你发现自己在数组元素上进行迭代,你应该寻找一种方法来重构你正在尝试的算法,这种方式只使用numpy操作(它有很多内置的!)或者如果真的有必要你可以使用np.apply_along_axis,np.apply_over_axisnp.vectorize.

  • 但是`list(np.arange(10))`和`np.arange(10).tolist()`之间有一个细微的区别:第一个会导致列表中的第二个`np.int64`列表of python`int`s.第一个可能是做序列化等问题,例如使用json.json会在第一次出错,因为它无法处理`np.int64` (2认同)

hpa*_*ulj 6

这些是我在较慢的机器上的时间

In [1034]: timeit [i for i in np.arange(10000000)]
1 loop, best of 3: 2.16 s per loop
Run Code Online (Sandbox Code Playgroud)

如果我直接生成范围(Py3所以这是一个发明者)时间要好得多.将此基线作为此大小的列表理解.

In [1035]: timeit [i for i in range(10000000)]
1 loop, best of 3: 1.26 s per loop
Run Code Online (Sandbox Code Playgroud)

tolist首先将arange转换为列表; 需要更长的时间,但迭代仍在列表中

In [1036]: timeit [i for i in np.arange(10000000).tolist()]
1 loop, best of 3: 1.6 s per loop
Run Code Online (Sandbox Code Playgroud)

使用list()- 同时直接迭代数组; 这表明直接迭代首先做到这一点.

In [1037]: timeit [i for i in list(np.arange(10000000))]
1 loop, best of 3: 2.18 s per loop

In [1038]: timeit np.arange(10000000).tolist()
1 loop, best of 3: 927 ms per loop
Run Code Online (Sandbox Code Playgroud)

同一次迭代.tolist

In [1039]: timeit list(np.arange(10000000))
1 loop, best of 3: 1.55 s per loop
Run Code Online (Sandbox Code Playgroud)

通常,如果必须循环,则在列表上工作会更快.访问列表元素更简单.

查看索引返回的元素.

a[0]是另一个numpy对象; 它是从值中构造的a,但不仅仅是取值

list(a)[0]是同一类型; 清单就是这样[a[0], a[1], a[2]]]

In [1043]: a = np.arange(3)
In [1044]: type(a[0])
Out[1044]: numpy.int32
In [1045]: ll=list(a)
In [1046]: type(ll[0])
Out[1046]: numpy.int32
Run Code Online (Sandbox Code Playgroud)

但是tolist将数组转换为纯列表,在本例中为int列表.它做的工作比以上更多list(),但在编译的代码中做了.

In [1047]: ll=a.tolist()
In [1048]: type(ll[0])
Out[1048]: int
Run Code Online (Sandbox Code Playgroud)

一般不要使用list(anarray).它很少有用,也没有那么强大tolist().

什么是迭代数组的最快方法 - 无.至少不是在Python中; 在c代码中有快速的方法.

a.tolist()是从数组创建列表整数的最快,矢量化方式.它迭代,但在编译代码中这样做.

但是你的真正目标是什么?