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

时间:2014-09-12 21:36:41

标签: python arrays performance numpy element

我最近遇到了great SO post,其中用户建议在处理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可靠得快?

4 个答案:

答案 0 :(得分:14)

不,不是很重要。

np.sumsum快的原因是sum被实现为“天真地”迭代迭代(在本例中为numpy数组),调用元素'{{ 1}}运算符(这会产生很大的开销),而numpy的__add__实现被优化,例如利用它知道元素的类型(dtype)的事实,并且它们在内存中是连续的。

sumnp.subtract(arr1, arr2)不是这种情况。后者粗略地转化为前者。

不同之处在于可以覆盖python中的减法运算符,因此numpy数组会覆盖它以使用优化版本。但是,arr1-arr2操作不可覆盖,因此numpy提供了另一种优化版本。

答案 1 :(得分:8)

不是真的。你可以很容易地检查时间。

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])这样的东西可以工作。

答案 2 :(得分:3)

@ shx2给出了很好的答案。

我将稍微展开sumnp.sum

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

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

顺便说一句,这也解释了为什么 dumb 使用Python standard-library C array type进行数学运算。 sum(list)比<{1}}快

答案 3 :(得分:1)

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])的文档显示它是ufuncufunc经常使用像__rsub__这样的已编译操作,但可能会增加一些开销以适应ufunc协议。

在其他一些案例中,np.foo(x, args)会转换为x.foo(args)

通常,如果函数和运算符最终调用编译的numpy代码来进行实际计算,那么时序将非常相似,特别是对于大型数组。