python – 用numpy进行矢量操作

我有三个numpy数组:

X:3073 x 49000矩阵
W:10×3073矩阵
y:49000 x 1向量

y包含0到9之间的值,每个值表示W中的一行.

我想将第一列X添加到y中第一个元素给出的W行中.即如果y中的第一个元素是3,则将X的第一列添加到W的第四行.然后将第二列X添加到y中第二个元素给出的W中的行,依此类推,直到所有列为X已经被y指定为W中的行,这意味着总共添加了49000行.

W [y] = X.T对我不起作用,因为这不会在W中的一行中添加多个向量.

请注意:我只是在寻找矢量化解决方案.即没有for循环.

编辑:为了澄清我将添加一个小矩阵大小的例子改编自萨尔瓦多达利的例子如下.

In [1]: import numpy as np

In [2]: a, b, c = 3, 4, 5

In [3]: np.random.seed(0)

In [4]: X = np.random.randint(10, size=(b,c))

In [5]: W = np.random.randint(10, size=(a,b))

In [6]: y = np.random.randint(a, size=(c,1))

In [7]: X
Out[7]: 
array([[5, 0, 3, 3, 7],
       [9, 3, 5, 2, 4],
       [7, 6, 8, 8, 1],
       [6, 7, 7, 8, 1]])

In [8]: W
Out[8]: 
array([[5, 9, 8, 9],
       [4, 3, 0, 3],
       [5, 0, 2, 3]])

In [9]: y
Out[9]: 
array([[0],
       [1],
       [1],
       [2],
       [0]])

In [10]: W[y.ravel()] + X.T
Out[10]: 
array([[10, 18, 15, 15],
       [ 4,  6,  6, 10],
       [ 7,  8,  8, 10],
       [ 8,  2, 10, 11],
       [12, 13,  9, 10]])

In [11]: W[y.ravel()] = W[y.ravel()] + X.T

In [12]: W
Out[12]: 
array([[12, 13,  9, 10],
       [ 7,  8,  8, 10],
       [ 8,  2, 10, 11]])

问题是将W中的BOTH第0列和第4列添加到W中的第0行,以及将X中的第1列和第2列添加到W中的第1行.

因此,期望的结果是:

W = [[17, 22, 16, 16],
     [ 7, 11, 14, 17],
     [ 8,  2, 10, 11]]

最佳答案 首先是直接循环解决方案作为参考:

In [65]: for i,j in enumerate(y):
    W[j]+=X[:,i]
   ....:     

In [66]: W
Out[66]: 
array([[17, 22, 16, 16],
       [ 7, 11, 14, 17],
       [ 8,  2, 10, 11]])

一个add.at解决方案:

In [67]: W=W1.copy()
In [68]: np.add.at(W,(y.ravel()),X.T)
In [69]: W
Out[69]: 
array([[17, 22, 16, 16],
       [ 7, 11, 14, 17],
       [ 8,  2, 10, 11]])

add.at执行无缓冲计算,绕过阻止W [y.ravel()] = X.T工作的缓冲.它仍然是迭代的,但循环已经移动到编译代码.这不是真正的矢量化,因为应用程序的顺序很重要.一行X.T的添加取决于前一行的结果.

https://stackoverflow.com/a/20811014/901925是我几年前给出类似问题的答案(对于1d阵列).

但是在处理大型数组时:

X: a 3073 x 49000 matrix
W: a 10 x 3073 matrix
y: a 49000 x 1 vector 

这可能会遇到速度问题.请注意,W [y.ravel()]的大小与X.T相同(为什么选择这些需要转置的大小?).这是一个副本,而不是一个视图.所以已经有时间惩罚了.

在之前的问题中已经提出了bincount,我认为它更快. Making for loop with index arrays faster(bincount和add.at解决方案)

迭代小的3073尺寸也可以具有速度优势.或者更好的是尺寸10维度,如Divakar所示.

对于小测试用例,a,b,c = 3,4,5,add.at解决方案最快,其次是Divakar的bincount和einseum.对于较大的a,b,c = 10,1000,20000,add.at变得非常慢,bincount是最快的.

相关的答案

https://stackoverflow.com/a/28205888/901925(注意到bincount需要完全覆盖y).

https://stackoverflow.com/a/30041823/901925(Divakar再次显示了bincount规则!)

点赞