在这篇文章中列出的是一个矢量化解决方案,在根据所涉及的计算将输入数组的维度扩展到 3D 和 4D 案例后,在各个位置使用 np.newaxis/None 大量使用 NumPy's powerful broadcasting feature。这是实现 -
# Get size of A
N = A.size
# Perform "(G - A[l])/(G + A[j]))" in a vectorized manner
p1 = (G - A[:,None,None,None])/(G + A[:,None,None])
# Perform "((A[l] - A[j])/(A[l] + A[j]))" in a vectorized manner
p2 = ((A[:,None] - A)/(A[:,None] + A))
# Elementwise multiplications between the previously calculated parts
p3 = p1*p2[...,None,None]
# Set the escaped portion "j != l" output as "G/A[l]"
p3[np.eye(N,dtype=bool)] = G/A[:,None,None]
Fout = p3.prod(1)
# If you need separate arrays just like in the question, split it
Fout_split = np.array_split(Fout,N)
示例运行 -
In [284]: # Original inputs
...: A = np.arange(1.,5.,1)
...: G = np.array([[1.,2.],[3.,4.]])
...:
In [285]: calcF(G,A)
Out[285]:
[array([[-0. , -0.00166667],
[-0.01142857, -0.03214286]]), array([[-0.00027778, 0. ],
[ 0.00019841, 0.00126984]]), array([[ 1.26984127e-03, 1.32275132e-04],
[ -0.00000000e+00, -7.93650794e-05]]), array([[-0.00803571, -0.00190476],
[-0.00017857, 0. ]])]
In [286]: vectorized_calcF(G,A) # Posted solution
Out[286]:
[array([[[-0. , -0.00166667],
[-0.01142857, -0.03214286]]]), array([[[-0.00027778, 0. ],
[ 0.00019841, 0.00126984]]]), array([[[ 1.26984127e-03, 1.32275132e-04],
[ -0.00000000e+00, -7.93650794e-05]]]), array([[[-0.00803571, -0.00190476],
[-0.00017857, 0. ]]])]
运行时测试-
In [289]: # Larger inputs
...: A = np.random.randint(1,500,(400))
...: G = np.random.randint(1,400,(20,20))
...:
In [290]: %timeit calcF(G,A)
1 loops, best of 3: 4.46 s per loop
In [291]: %timeit vectorized_calcF(G,A) # Posted solution
1 loops, best of 3: 1.87 s per loop
使用 NumPy/MATLAB 进行向量化:一般方法
感觉我可以在我的一般方法上投入两分钱,我认为其他人在尝试矢量化代码时会遵循类似的策略,尤其是在 NumPy 或 MATLAB 等高级平台中。所以,这里有一个可以考虑Vectorization的事情的快速清单-
关于扩展维度的想法:将扩展输入数组的维度,以便新维度包含原本在嵌套循环中迭代生成的结果。
从哪里开始向量化?从计算的最深(代码迭代最多的循环)阶段开始,看看如何扩展输入并引入相关计算。注意跟踪所涉及的迭代器并相应地扩展维度。向外移动到外部循环,直到您对完成的矢量化感到满意。
如何处理条件语句? 对于简单的情况,蛮力计算一切,然后看看如何处理 IF/ELSE 部分。这将是高度特定的上下文。
是否存在依赖关系?如果有,请查看是否可以相应地跟踪和实施依赖关系。这可能会形成另一个讨论话题,但这里是few examples 我自己参与其中。