Numpy 自动逐元素函数

Numpy automatic elementwise function

我有一个关于 numpy 的问题。

假设我有一个函数

def calcSomething(A,t):

    return t*A

我想向 A 传递一个常量 numpy 数组,例如A=np.array([1.0,2.0]) 和 t 为等距点,例如t = np.linspace(0.0,1.0,10)。 现在,当我执行

x = calcSomething(A,t)

我想要 x[0] = [0,0]x[1] = [.1,.2]、...、x[9] = [1.0,2.0]。有没有一种简单的方法可以实现它,还是我必须使用 for 循环和追加来实现它?

编辑:'calcSomething(): 只是一个更复杂函数的占位符。

例如y=np.sin(t) 产生 y[i]=np.sin(t[i])。这就是我想要实现的通用功能。

提前致谢!

可以使用矩阵乘法:

>>> A = np.array([1.0,2.0])
>>> t = np.linspace(0.0,1.0,10)
>>> np.matmul(t.reshape(10, 1), A.reshape(1, 2))
array([[0.        , 0.        ],
       [0.11111111, 0.22222222],
       [0.22222222, 0.44444444],
       [0.33333333, 0.66666667],
       [0.44444444, 0.88888889],
       [0.55555556, 1.11111111],
       [0.66666667, 1.33333333],
       [0.77777778, 1.55555556],
       [0.88888889, 1.77777778],
       [1.        , 2.        ]])

只需使用None指定一个新轴:

A[None, :] * t[:, None] 

在可能的情况下,使用对整个数组进行运算的 numpy 函数和运算符,并为您做必要的 broadcasting

In [24]: A = np.array([1.0,2.0]); t = np.linspace(0.0, 1.0, 10)
In [25]: x = t[:,None] * A[None,:]
In [26]: x.shape
Out[26]: (10, 2)
In [27]: x[:3,:]
Out[27]: 
array([[0.        , 0.        ],
       [0.11111111, 0.22222222],
       [0.22222222, 0.44444444]])
In [28]: np.sin(t)
Out[28]: 
   array([0.        , 0.11088263, 0.22039774, 0.3271947 , 0.42995636,
          0.52741539, 0.6183698 , 0.70169788, 0.77637192, 0.84147098])

如果您有一个仅适用于标量输入的函数,您可以使用 np.vectorize 为它提供这些值 - 来自广播数组:

In [30]: def foo(A,t):
    ...:     return t*A
    ...: 
In [31]: f = np.vectorize(foo, otypes=[float])
In [32]: f(A[None,:], t[:,None])
Out[32]: 
array([[0.        , 0.        ],
       [0.11111111, 0.22222222],
       [0.22222222, 0.44444444],
       ....
       [1.        , 2.        ]])

vectorize 是一个方便的函数;它不保证速度。将其时间与 In[25] 进行比较:

In [33]: timeit f(A[None,:], t[:,None])
41.3 µs ± 48.5 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [34]: timeit x = t[:,None] * A[None,:]
5.41 µs ± 8.2 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

8 倍慢。

或使用标量 math.sin 函数:

In [35]: import math
In [36]: g = np.vectorize(math.sin)
...
In [39]: timeit g(t)
39 µs ± 72.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)
In [40]: timeit np.sin(t)
1.4 µs ± 2.72 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

迭代调用 math.sinnp.sin 快,但是 np.sin 在给定整个数组时要快得多。

基本区别在于 vectorize,就像显式循环在解释 Python 中迭代一样,并为每个输出元素调用一次函数。 np.sin 和数组 * 正在迭代,但在编译代码中。

在 Python 和 numpy 中有多种迭代方法,但它们很少能给你超过 2 倍的加速。

有将计算移动到编译代码的工具,例如cythonnumba。搜索这些标签以了解如何使用它们。