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