简体   繁体   English

Python Numpy 沿第二维和第三维向量化

[英]Python Numpy vectorizing along second and third dimension

I want to vectorize the calculation along the second and third axis, but I cannot find a way to deal with the last for loop:我想将计算沿第二个和第三个轴矢量化,但我找不到处理最后一个 for 循环的方法:

n = 3000
D = 2000
delta = np.arrange(D * n).reshape(D, n)
M = np.arrange(D * n * n).reshape(D, n, n)
result = np.zeros(D, n)
for i in range(D):
    result[i, :] = np.dot(delta[i, :], M[i, :, :])

Let's construct a small example (no need to use big sizes like 3000):让我们构建一个小例子(不需要使用像 3000 这样的大尺寸):

In [122]: n,D = 3,2                                                             
In [123]: delta = np.arange(D*n).reshape(D,n)    # not arrange                                   
In [124]: M = np.arange(D*n*n).reshape(D,n,n)                                   
In [125]: result = np.zeros(D, n) 
     ...: for i in range(D): 
     ...:     result[i, :] = np.dot(delta[i, :], M[i, :, :]) 
     ...:                                                                       
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-125-413de80d25a5> in <module>
----> 1 result = np.zeros(D, n)
      2 for i in range(D):
      3     result[i, :] = np.dot(delta[i, :], M[i, :, :])
      4 

TypeError: data type not understood

Oops, your np.zeros call is wrong!糟糕,您的np.zeros调用是错误的!

In [126]: result = np.zeros((D, n),int) 
     ...: for i in range(D): 
     ...:     result[i, :] = np.dot(delta[i, :], M[i, :, :]) 
     ...:                                                                       
In [127]: result                                                                
Out[127]: 
array([[ 15,  18,  21],
       [150, 162, 174]])

einsum is a handy way of matching diverse dimensions. einsum是一种匹配不同维度的便捷方式。 Note how the i dimension matches yours.请注意i维度如何与您的相匹配。

In [128]: np.einsum('ij,ijk->ik',delta, M)                                      
Out[128]: 
array([[ 15,  18,  21],
       [150, 162, 174]])

Let's try the matmul/@ function which is supposed to handle 'batch' dots like yours:让我们试试matmul/@ function 它应该可以处理像你这样的“批处理”点:

In [129]: np.matmul(delta, M)                                                   
Out[129]: 
array([[[ 15,  18,  21],
        [ 42,  54,  66]],

       [[ 42,  45,  48],
        [150, 162, 174]]])
In [130]: _.shape                                                               
Out[130]: (2, 2, 3)

Oops, too much.哎呀,太多了。 Let's add a dimension to delta to make it (D,1,n).让我们为delta添加一个维度以使其成为 (D,1,n)。 That way the D dimension is consistently the first of 3:这样, D维度始终是 3 个维度中的第一个:

In [131]: np.matmul(delta[:,None,:], M)                                         
Out[131]: 
array([[[ 15,  18,  21]],

       [[150, 162, 174]]])

Those are the correct values, but the shape is (2,1,3).这些是正确的值,但形状是 (2,1,3)。 We can get rid of that middle dimension with reshape or index or squeeze:我们可以通过 reshape 或 index 或挤压来摆脱那个中间维度:

In [132]: np.matmul(delta[:,None,:], M).squeeze()                               
Out[132]: 
array([[ 15,  18,  21],
       [150, 162, 174]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM