numpy.sum
比Python的sum
更快。这使我思考,对NumPy数组进行逐元素操作时,使用NumPy函数是否比运算符更快?如果是这样,为什么呢?
考虑以下示例。
import numpy as np
a = np.random.random(1e10)
b = np.random.random(1e10)
< p > np.subtract(a, b)
是否比 a - b
更可靠地快?< /p >
numpy.sum
比Python的sum
更快。import numpy as np
a = np.random.random(1e10)
b = np.random.random(1e10)
< p > np.subtract(a, b)
是否比 a - b
更可靠地快?< /p >
不,没有显著的区别。
np.sum
更快的原因是sum
被实现为“简单地”迭代可迭代对象(在这种情况下,是numpy数组),调用元素的__add__
运算符(这会带来显著的开销),而numpy的sum
实现则经过了优化,例如利用它知道元素类型(dtype)以及它们在内存中是连续的等特点。
但对于np.subtract(arr1,arr2)
和arr1-arr2
,情况并非如此。后者大致相当于前者。
差异在于,可以在Python中重写减法运算符,所以numpy数组覆盖它以使用优化版本。 然而,sum
操作是不可重写的,因此numpy提供了替代的优化版本。
不完全是。但你可以很容易地检查时间。
a = np.random.normal(size=1000)
b = np.random.normal(size=1000)
%timeit np.subtract(a, b)
# 1000000 loops, best of 3: 1.57 µs per loop
%timeit a - b
# 1000000 loops, best of 3: 1.47 µs per loop
%timeit np.divide(a, b)
# 100000 loops, best of 3: 3.51 µs per loop
%timeit a / b
# 100000 loops, best of 3: 3.38 µs per loop
numpy的函数似乎慢了一点,我不确定这是否重要,但我怀疑除了相同实现之外,还有一些额外的函数调用开销。
编辑:正如@unutbu所指出的那样,这可能是因为np.add
和其他函数在必要时需要将类似数组的对象转换为数组,从而增加了类型检查的开销,以便处理像np.add([1,2],[3,4])
这样的操作。
@shx2的回答很好。
我稍微解释一下sum
和np.sum
的不同:
sum
会遍历数组,逐个将元素转换为Python对象,然后将它们作为Python对象相加。np.sum
使用本地代码中的优化循环对数组进行求和,而不需要转换单个值(正如shx2所指出的那样,这要求数组内容具有同质性和连续性)。每个数组元素的转换为Python对象是开销最大的来源。
顺便说一下,这也说明为什么使用Python的标准库C数组类型进行数学运算是愚蠢的。 sum(list)
比sum(array.array)
快得多。
a-b
被翻译为函数调用 a.__rsub__(b)
。因此,它使用属于变量的方法(例如,如果 a
是数组,则使用已编译的 numpy 代码)。
In [20]: a.__rsub__??
Type: method-wrapper
String Form:<method-wrapper '__rsub__' of numpy.ndarray object at 0xad27a88>
Docstring: x.__rsub__(y) <==> y-x
np.subtract(x1, x2[, out])
的文档显示它是一个ufunc
。 ufunc
通常使用编译操作,如__rsub__
,但可能会增加一些开销以适应ufunc
协议。
在许多其他情况下,np.foo(x, args)
转换为x.foo(args)
。
一般来说,如果函数和运算符最终调用编译的numpy代码来执行实际计算,则计时将非常相似,特别是对于大数组。
np.subtract
包含将其参数转换为数组的额外代码,因此np.subtract([1,2,3],[4,5,6])
是可行的。a-b
不需要这个额外的代码,所以它稍微快一点。np.subtract
还可以处理out
关键字参数... - unutbunp.subtract
的这两个附加功能都是函数进入/退出时的一次性问题。如果您不使用它们,则它们是O(1)
,因此随着数组越来越大,它们将变得越来越微不足道。 - Dan Lenski