为什么要根据速度使用 numpy over list?

Pak*_*ong 5 python arrays numpy

参考为什么使用 NumPy 而不是 Python 列表?

tom10 说:

速度:这是对列表和 NumPy 数组进行求和的测试,表明 NumPy 数组上的求和速度快 10 倍(在此测试中——里程可能会有所不同)。

但我的测试使用以下代码:

import numpy as np
import time as time

N = 100000

#using numpy
start = time.time()
array = np.array([])

for i in range(N):
    array = np.append(array, i)

end = time.time()
print ("Using numpy: ", round(end-start, 2), end="\n")

#using list
start = time.time()
list = []

for i in range(N):
    list.append(i)

list = np.array(list)   
end = time.time()
print ("Using list : ", round(end-start, 2), end="\n")
Run Code Online (Sandbox Code Playgroud)

给出结果:

Using numpy: 8.35
Using list : 0.02
Run Code Online (Sandbox Code Playgroud)

确实,在使用“append”时, list 比 numpy 好?

use*_*699 5

要回答你的问题,是的。追加到数组是一项昂贵的操作,而列表使它相对便宜(请参阅Python 列表的内部结构、访问和调整运行时大小以了解原因)。然而,这不是放弃 numpy 的理由。还有其他方法可以轻松地将数据添加到 numpy 数组。

有很多令人惊讶的(对我来说,无论如何)方法来做到这一点。跳到底部以查看每个的基准。

可能最常见的是简单地预先分配数组,并索引到其中,

#using preallocated numpy
start = time.time()
array = np.zeros(N)

for i in range(N):
    array[i] = i

end = time.time()
print ("Using preallocated numpy: ", round(end-start, 5), end="\n")
Run Code Online (Sandbox Code Playgroud)

当然,您也可以为列表预先分配内存,因此让我们将其包含在基准比较中。

#using preallocated list
start = time.time()
res = [None]*N

for i in range(N):
    res[i] = i

res = np.array(res)
end = time.time()
print ("Using preallocated list : ", round(end-start, 5), end="\n")
Run Code Online (Sandbox Code Playgroud)

根据您的代码,使用 numpy 的fromiter函数也可能会有所帮助,该函数使用迭代器的结果来初始化数组。

#using numpy fromiter shortcut
start = time.time()

res = np.fromiter(range(N), dtype='float64') # Use same dtype as other tests

end = time.time()
print ("Using fromiter : ", round(end-start, 5), end="\n")
Run Code Online (Sandbox Code Playgroud)

当然,使用内置迭代器并不是非常灵活,所以让我们也尝试一下自定义迭代器,

#using custom iterator
start = time.time()
def it(N):
    i = 0
    while i < N:
        yield i
        i += 1

res = np.fromiter(it(N), dtype='float64') # Use same dtype as other tests

end = time.time()
print ("Using custom iterator : ", round(end-start, 5), end="\n")
Run Code Online (Sandbox Code Playgroud)

这是两种非常灵活的使用numpy. 第一种,使用预先分配的数组,是最灵活的。让我们看看他们是如何比较的:

Using numpy:  2.40017
Using list :  0.0164
Using preallocated numpy:  0.01604
Using preallocated list :  0.01322
Using fromiter :  0.00577
Using custom iterator :  0.01458
Run Code Online (Sandbox Code Playgroud)

马上,您可以看到预分配numpy比使用列表快得多,尽管预分配列表使两者的速度大致相同。使用内置迭代器非常快,尽管在使用自定义迭代器时迭代器的性能会回落到预分配数组和列表的范围内。

将代码直接转换为numpy通常性能较差,如append. 使用numpy的方法找到一种方法几乎总是可以带来实质性的改进。在这种情况下,预先分配数组或将每个元素的计算表示为迭代器以获得与 python 列表类似的性能。或者使用 vanilla python 列表,因为性能大致相同。

编辑:原始答案也包括np.fromfunction。这被删除了,因为它不适合一次添加一个元素的用例,fromfunction实际上初始化数组并使用numpy的广播来进行单个函数调用。它大约快一百倍,所以如果您可以使用广播解决您的问题,请不要使用这些其他方法。