如何提高numpy数组的效率?
我刚开始接触numpy,听说它在内存访问方面的效率跟C语言差不多,这让我很惊讶。我想亲自看看numpy的ndarrays和普通的Python列表有什么区别,于是我做了个简单的时间测试,分别用numpy和普通列表做了一些相同的简单任务。结果果然,numpy在分配数组和进行数学运算方面比普通列表快了很多倍。不过,有一段代码在两个测试中是完全相同的,使用普通列表时大约只花了1/8秒,而用numpy却花了超过2.5秒:
file = open('timing.log','w')
for num in a2:
if num % 1000 == 0:
file.write("Multiple of 1000!\r\n")
file.close()
有没有人知道这是为什么?我是否应该使用其他语法来进行这样的操作,以更好地利用ndarray的功能?
谢谢...
补充说明:为了回应Wayne的评论... 我多次测试了这两个,顺序也不一样,每次结果几乎都一样,所以我怀疑不是其他进程的问题。我把
start = time()
放在文件顶部,在numpy导入之后,然后在文件中有像print 'Time after traversal:\t',(time() - start)
这样的语句。
3 个回答
5
对numpy数组进行逐个元素访问会非常慢。建议使用向量操作:
$ python -mtimeit -s 'import numpy as np; a2=np.arange(10**6)' '
> sum(1 for i in a2 if i % 1000 == 0)'
10 loops, best of 3: 1.53 sec per loop
$ python -mtimeit -s 'import numpy as np; a2=np.arange(10**6)' '
> (a2 % 1000 == 0).sum()'
10 loops, best of 3: 22.6 msec per loop
$ python -mtimeit -s 'import numpy as np; a2= range(10**6)' '
> sum(1 for i in a2 if i % 1000 == 0)'
10 loops, best of 3: 90.9 msec per loop
6
我并不惊讶你用的代码片段在性能上NumPy表现得不如Python自带的功能。NumPy的一个重要优势就是它能避免使用循环,而是通过索引直接访问数组,这样可以提高性能。
在NumPy中,通常会这样做:
A = NP.random.randint(10, 100, 100).reshape(10, 10)
w = A[A % 2 == 0]
NP.save("test_file.npy", w)
10
a2
是一个 NumPy 数组,对吧?如果它在 NumPy 中运行得很慢(假如其他进程的活动不是原因,就像 Wayne Werner 提到的那样),一个可能的原因是你在用 Python 的循环来遍历这个数组。在每一步循环中,Python 都需要从 NumPy 数组中取出一个值,并把它转换成 Python 的整数,这个过程其实并不快。
NumPy 在你能对整个数组进行操作时效果会更好。在你的情况下,有一个选择(可能不是最快的)是
file.write("Multiple of 1000!\r\n" * (a2 % 1000 == 0).sum())
你可以试着把这个和纯 Python 的做法进行比较,
file.write("Multiple of 1000!\r\n" * sum(filter(lambda i: i % 1000 == 0, a2)))
或者
file.write("Multiple of 1000!\r\n" * sum(1 for i in a2 if i % 1000 == 0))