在可能的情况下,使用对整个数组进行操作的 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.sin
比 快np.sin
,但np.sin
在给定整个数组时要快得多。
基本区别在于vectorize
,像显式循环一样,它在解释的 Python 中进行迭代,并为每个输出元素调用一次函数。 np.sin
并且数组*
正在迭代,但是在编译的代码中。
在 Python 和 numpy 中有多种迭代方式,但很少有超过 2 倍的加速。
有一些工具可以将计算转移到已编译的代码中,例如cython
和numba
。搜索这些标签以获取有关如何使用它们的想法。