我有三个numpy数组:
X
:3073 x 49000矩阵
W
:10 x 3073矩阵
y
:49000 x 1向量
y
包含0到9之间的值,每个值代表W
中的一行。
我想将X
的第一列添加到W
中第一个元素给出的y
行中。即如果y
中的第一个元素为3,则将X
的第一列添加到W
的第四行。然后将X
的第二列添加到W
中由y
中的第二个元素指定的行中,依此类推,直到X
的所有列都已添加到W
由y
指定的W[y] += X.T
行,表示总共添加了49000行。
W
对我不起作用,因为这不会在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]])
的行中添加多个向量。
请注意:我只是在寻找 矢量化 解决方案。即没有for-loops。
编辑:为了澄清我将添加一个小矩阵大小的示例,该示例改编自Salvador Dali的示例。
W = [[17, 22, 16, 16],
[ 7, 11, 14, 17],
[ 8, 2, 10, 11]]
问题是将 BOTH 列0和X中的第4列添加到W中的第0行,以及将X中的第1列和第2列添加到W中的第1行。
因此,期望的结果是:
my code
HtmlElementCollection bColl = webBrowser1.Document.GetElementsByTagName("td");
foreach (HtmlElement bEl in bColl)
{
if (bEl.GetAttribute("b").Contains("your"))
txtLinkDetails.Text = bEl.OuterHtml.Split('"')[3].Replace("&", "&");
}
答案 0 :(得分:3)
方法#1
基于this answer
,这是使用np.bincount
的矢量化解决方案 -
N = y.max()+1
id = y.ravel() + np.arange(X.shape[0])[:,None]*N
W[:N] += np.bincount(id.ravel(), weights=X.ravel()).reshape(-1,N).T
方法#2
您可以充分利用boolean indexing
和np.einsum
以简洁的矢量化方式完成工作 -
N = y.max()+1
W[:N] += np.einsum('ijk,lk->il',(np.arange(N)[:,None,None] == y.ravel()),X)
方法#3
由于您从X
每个唯一y
选择并添加了大量列,因此在性能方面运行与complexity
等于此类唯一y's
的数量,似乎在max
等于W
中的行数,而在您的情况下仅为10
。因此,循环只有10次迭代,不错!这是实现这些愿望的实施 -
for k in range(W.shape[0]):
W[k] += X[:,(y==k).ravel()].sum(1)
方法#4
你可以引入np.einsum
来进行列式求和,并得到最终输出 -
for k in range(W.shape[0]):
W[k] += np.einsum('ij->i',X[:,(y==k).ravel()])
答案 1 :(得分:3)
首先将直接循环解决方案作为参考:
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'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
规则!)
答案 2 :(得分:1)
这将实现您的目标:X + W[y.ravel()].T
要看到这确实有效,这是一个可重复的例子:
import numpy as np
np.random.seed(0)
a, b, c = 3, 5, 4 # you can use your 3073, 49000, 10 later
X = np.random.rand(a, b)
W = np.random.rand(c, a)
y = np.random.randint(c, size=(b, 1))
现在你的矩阵是:
[[ 0.0871293 0.0202184 0.83261985]
[ 0.77815675 0.87001215 0.97861834]
[ 0.79915856 0.46147936 0.78052918]
[ 0.11827443 0.63992102 0.14335329]]
[[3]
[0]
[3]
[2]
[0]]
[[ 0.5488135 0.71518937 0.60276338 0.54488318 0.4236548 ]
[ 0.64589411 0.43758721 0.891773 0.96366276 0.38344152]
[ 0.79172504 0.52889492 0.56804456 0.92559664 0.07103606]]
W[y.ravel()]
给你"由y"中的第一个元素给出的W通过转置它,您将获得一个准备好添加到X的矩阵:
[[ 0.11827443 0.0871293 0.11827443 0.79915856 0.0871293 ]
[ 0.63992102 0.0202184 0.63992102 0.46147936 0.0202184 ]
[ 0.14335329 0.83261985 0.14335329 0.78052918 0.83261985]]
答案 3 :(得分:0)
虽然我不能说这是非常pythonic,但这是一个解决方案(我认为):
for column in range(x.shape[1]):
w[y[column]] = x[:,column].T