【发布时间】:2017-01-15 05:03:35
【问题描述】:
已经问过这个问题的不同版本,但我没有找到满意的答案。
问题:给定一个大的 numpy 向量,找到重复的向量元素的索引(其变化可以与容差进行比较)。
所以问题是〜O(N ^ 2)和内存限制(至少从当前算法的角度来看)。我想知道为什么我尝试过的 Python 比等效的 C 代码慢 100 倍或更多。
import numpy as np
N = 10000
vect = np.arange(float(N))
vect[N/2] = 1
vect[N/4] = 1
dupl = []
print("init done")
counter = 0
for i in range(N):
for j in range(i+1, N):
if vect[i] == vect[j]:
dupl.append(j)
counter += 1
print("counter =", counter)
print(dupl)
# For simplicity, this code ignores repeated indices
# which can be trimmed later. Ref output is
# counter = 3
# [2500, 5000, 5000]
我尝试使用 numpy 迭代器,但它们更糟糕(~ x4-5) http://docs.scipy.org/doc/numpy/reference/arrays.nditer.html
使用 N=10,000 我在 C 中得到 0.1 秒,在 Python 中得到 12 秒(上面的代码),在 Python 中使用 np.nditer 得到 40 秒,在 Python 中使用 np.ndindex 得到 50 秒。我把它推到 N=160,000 并且时间按预期缩放为 N^2。
【问题讨论】:
-
因为 Python 很慢?
-
numpy 数组在使用内置 numpy 函数(在 C 中实现)时非常有效。无论您是否使用 numpy,Python 循环都很慢。尝试仅使用 numpy 函数来实现您的算法。使用内置 Python 函数和/或推导式还应该提高性能(低于 numpy 但高于普通循环)。
-
因此,Python 中的循环也不错。无论如何,循环有什么困难。我怀疑它的嵌套循环正在杀死这段代码(创建另一个上下文?)
-
我不想回答我自己的问题,但我最终通过求助于 Numba 解决了。一开始还记得,后来忘记了。时间几乎就是 C 编译代码给我的时间,而且还有一个 Python 循环。所以外循环不是问题。我感谢所有关于使用库的 cmets。实际上,必须使用它们才能获得最佳性能。但是,我发现很难记住所有这些调用,并且从代码而不是库的角度思考对我来说更容易。
-
nditer页面以cython示例结尾。那是你获得了一些速度。否则nditer只是处理多输入和输出广播的一种方式。
标签: python arrays loops numpy optimization