繁体   English   中英

使用NumPy函数的元素操作比运算符更快吗?

[英]Are element-wise operations faster with NumPy functions than operators?

我最近遇到了一篇很棒的帖子 ,其中一位用户建议在处理NumPy数组时, numpy.sum比Python的sum更快。

这让我想到,使用NumPy函数比运算符更快地对NumPy数组进行元素操作? 如果是这样,那为什么会这样呢?

请考虑以下示例。

import numpy as np
a = np.random.random(1e10)
b = np.random.random(1e10)

np.subtract(a, b)是否比a - b可靠得快?

不,不是很重要。

np.sumsum更快的原因是, 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])这样的东西np.add([1, 2], [3, 4])作品。

@ shx2给出了很好的答案。

我将略微扩展sumnp.sum

  • 内置的sum将通过一个数组,逐个获取元素并将它们转换为Python对象,然后将它们作为Python对象一起添加。
  • np.sum将使用本机代码中的优化循环对数组求和,而不对单个值进行任何转换(正如shx2指出的那样,这至关重要的是需要数组内容的同质性和连续性)

到目前为止,每个数组元素到Python对象的转换是开销的主要来源。

顺便说一句,这也解释了为什么使用Python的标准库C数组类型进行数学运算是愚蠢的。 sum(list)sum(array.array) 要快得多

ab转换为函数调用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代码来进行实际计算,则时序将非常相似,尤其是对于大型数组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM