我有三个 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,5
, add.at
解决方案最快,其次是 Divakar's
bincount
和 einseum
。对于较大的 a,b,c=10,1000,20000
, add.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/