【发布时间】:2020-06-13 21:06:55
【问题描述】:
问题:
当使用广播而不是广播标量来匹配数组时,向量化函数会出于某种原因将数组缩小为标量。
MWE:
下面是 MWE。它包含一个双 for 循环。我无法编写不使用 for 循环而是使用广播/矢量化 numpy 的更快代码。
import numpy as np
def OneD(x, y, z):
ret = np.exp(x)**(y+1) / (z+1)
return ret
def ThreeD(a,b,c):
value = OneD(a[0],b[0], c)
value *= OneD(a[1],b[1], c)
value *= OneD(a[2],b[2], c)
return value
M_1 = M_2 = [[0,0,0],[0,0,1], [1,1,1], [1,0,2]]
scales0 = scales1 = [1.1, 2.2, 3.3, 4.4]
cc0 = cc1 = 1.77
results = np.zeros((4,4))
for s0, n0, in enumerate(M_1):
for s1, n1, in enumerate(M_2):
v = ThreeD(n0, n1, s1)
v *= cc0 * cc1 * scales0[s0] * scales1[s1]
results[s0, s1] += v
虽然我想删除两个 for 循环,但为了简单起见,我首先尝试摆脱内部循环。不过,请随意回答这两个问题。
尝试失败:
这是我改变循环的方式
rr = [0,1,2,3]
myfun = np.vectorize(ThreeD)
for s0, n0, in enumerate(M_1):
#for s1, n1, in enumerate(M_2):
v = myfun(n0, M_2, rr)
v *= cc0 * cc1 * scales0[s0] * scales1[rr]
results[s0, rr] += v
错误信息:
Traceback (most recent call last):
File "main.py", line 36, in <module>
v = myfun(n0, M_2, rr)
File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1573, in __call__
return self._vectorize_call(func=func, args=vargs)
File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1633, in _vectorize_call
ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args)
File "/usr/lib/python3/dist-packages/numpy/lib/function_base.py", line 1597, in _get_ufunc_and_otypes
outputs = func(*inputs)
File "main.py", line 18, in ThreeD
value = OneD(a[0],b[0], c)
IndexError: invalid index to scalar variable.
我还需要矢量化OneD 函数吗?我希望通过对ThreeD 函数进行矢量化处理,它会进行适当的记账。
【问题讨论】:
-
我开始怀疑使用 np.vectorize 是否会使其更快,即使它确实有效......
-
np.vectorize承诺什么样的加速? -
没有,这就是问题所在。所以我完全不知道如何加快速度。
-
np.vectorize确实将输入相互广播,将标量值传递给函数。您的OneD已经完全“矢量化”。只要“广播”,它将在任何维度的x,y,z上工作。如果不仔细检查,我怀疑ThreeD可能类似于OneD(a, b, c).sum(axis=0)。 -
我已经尝试过对
ThreeD进行矢量化,但它实际上减慢了它的速度。在调用OneD之前,我使用了np.vectorize(OneD)的np.prod(OneD)。不过没关系。如果可以的话,我主要关心的是完全摆脱双重for loops。这需要广播,而我的大脑没有……广播。
标签: python-3.x performance numpy vectorization array-broadcasting