我有三个 numpy 数组:
X : 一个 3073 x 49000 的矩阵W : 一个 10 x 3073 的矩阵y : 一个 49000 x 1 的向量
y 包含 0 到 9 之间的值,每个值代表 W 中的一行。

我想将 X 的第一列添加到 W 中第一个元素给出的 y 行中。 IE。如果 y 中的第一个元素是 3,则将 X 的第一列添加到 W 的第四行。然后将 X 的第二列添加到 W 中第二个元素给出的 y 中的行中,依此类推,直到 X 的所有列都添加到 W 指定的 y 中的行中,即总共添加了 49000 行。
W[y] += X.T 对我不起作用,因为这不会向 W 中的一行添加一个以上的向量。

请注意 :我只是在寻找 向量化 解决方案。 IE。没有 for 循环。

编辑: 为澄清起见,我将添加一个示例,其中包含改编自萨尔瓦多·达利 (Salvador Dali) 示例的小矩阵大小。

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]])

问题是将 X 中的第 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 是我几年前对类似问题(对于一维数组)给出的答案。

但是在处理大型数组时:
X: a 3073 x 49000 matrix
W: a 10 x 3073 matrix
y: a 49000 x 1 vector

这可能会遇到速度问题。请注意,W[y.ravel()]X.T 的大小相同(为什么选择这些需要转置的大小?)。这是一个副本,而不是一个 View 。所以已经有时间惩罚了。
bincount 已经在之前的问题中提出了,我认为它更快。 Making for loop with index arrays faster(bincount 和 add.at 解决方案)

迭代较小的 3073 维度也可能具有速度优势。或者在 Divakar 演示的大小为 10 的维度上更好。

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

相关的 SO 答案

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

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

关于python - 使用 numpy 进行向量运算,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/32283082/

10-12 21:33