Python 是否有numpy/scipy点积,仅计算结果的对角线条目?
想象一下有2个numpy阵列:Python 是否有numpy/scipy点积,仅计算结果的对角线条目?,python,numpy,scipy,product,Python,Numpy,Scipy,Product,想象一下有2个numpy阵列: > A, A.shape = (n,p) > B, B.shape = (p,p) 通常,p是一个较小的数字(p我想我是自己得到的,但是我将分享解决方案: 因为只得到矩阵乘法的对角线 > Z = N.diag(X.dot(Y)) 相当于X行和Y列的标量积的单个和,前面的语句相当于: > Z = (X * Y.T).sum(-1) 对于原始变量,这意味着: > result = (A.dot(B) * A).sum(-1) 如果
> A, A.shape = (n,p)
> B, B.shape = (p,p)
通常,p是一个较小的数字(p我想我是自己得到的,但是我将分享解决方案: 因为只得到矩阵乘法的对角线
> Z = N.diag(X.dot(Y))
相当于X行和Y列的标量积的单个和,前面的语句相当于:
> Z = (X * Y.T).sum(-1)
对于原始变量,这意味着:
> result = (A.dot(B) * A).sum(-1)
如果我错了,请纠正我,但这应该是它…你几乎可以得到任何你曾经梦想过的东西。在你开始掌握窍门之前,它基本上看起来像黑色巫术
>>> a = np.arange(15).reshape(5, 3)
>>> b = np.arange(9).reshape(3, 3)
>>> np.diag(np.dot(np.dot(a, b), a.T))
array([ 60, 672, 1932, 3840, 6396])
>>> np.einsum('ij,ji->i', np.dot(a, b), a.T)
array([ 60, 672, 1932, 3840, 6396])
>>> np.einsum('ij,ij->i', np.dot(a, b), a)
array([ 60, 672, 1932, 3840, 6396])
编辑你实际上可以在一次拍摄中获得整个画面,这太荒谬了
>>> np.einsum('ij,jk,ki->i', a, b, a.T)
array([ 60, 672, 1932, 3840, 6396])
>>> np.einsum('ij,jk,ik->i', a, b, a)
array([ 60, 672, 1932, 3840, 6396])
编辑不过,你不想让它自己占据太多的位置……还为自己的问题添加了OP的答案,以供比较
n, p = 10000, 200
a = np.random.rand(n, p)
b = np.random.rand(p, p)
In [2]: %timeit np.einsum('ij,jk,ki->i', a, b, a.T)
1 loops, best of 3: 1.3 s per loop
In [3]: %timeit np.einsum('ij,ij->i', np.dot(a, b), a)
10 loops, best of 3: 105 ms per loop
In [4]: %timeit np.diag(np.dot(np.dot(a, b), a.T))
1 loops, best of 3: 5.73 s per loop
In [5]: %timeit (a.dot(b) * a).sum(-1)
10 loops, best of 3: 115 ms per loop
避免构建大型中间阵列的简单答案是:
result=np.empty([n,], dtype=A.dtype )
for i in xrange(n):
result[i]=A[i,:].dot(B).dot(A[i,:])
+1智能代数总是比复杂的算法好。如果有人是numpy新手,这里的重点是X.dot(Y)运算符和*运算符X.dot(Y)之间的区别表示线性代数中的常规矩阵积,而X*Y返回X和Y项之间的逐点积,因此X和Y需要具有相同的形状。我不知道这个函数,但现在肯定会知道。Thx用于共享!!!我相信[3]依赖于“点”是高度优化的c代码这一事实(blas?)但是这确实构造了一个潜在的大型中间数组。我不确定np.einsum('ij,ij->I',np.dot(a,b,a)给出了什么,但它肯定是一个不同于Z=N.diag(X.dot(Y))的结果,Z=N.diag(X.dot(Y))的结果,它提供了点积的对角线元素(在本例中为[15,54,111])。
[N.]
不是有效的Python。你是说A.shape
?@wkschwartz已修复。不,只是预先分配结果数组。
n, p = 10000, 200
a = np.random.rand(n, p)
b = np.random.rand(p, p)
In [2]: %timeit np.einsum('ij,jk,ki->i', a, b, a.T)
1 loops, best of 3: 1.3 s per loop
In [3]: %timeit np.einsum('ij,ij->i', np.dot(a, b), a)
10 loops, best of 3: 105 ms per loop
In [4]: %timeit np.diag(np.dot(np.dot(a, b), a.T))
1 loops, best of 3: 5.73 s per loop
In [5]: %timeit (a.dot(b) * a).sum(-1)
10 loops, best of 3: 115 ms per loop
result=np.empty([n,], dtype=A.dtype )
for i in xrange(n):
result[i]=A[i,:].dot(B).dot(A[i,:])