我有一个k*n
矩阵X和一个k*k
矩阵A.对于X
的每一列,我想计算标量
X[:, i].T.dot(A).dot(X[:, i])
(或者,数学上,Xi' * A * Xi
)。
目前,我有一个for
循环:
out = np.empty((n,))
for i in xrange(n):
out[i] = X[:, i].T.dot(A).dot(X[:, i])
但由于n
很大,如果可能的话我想更快地做到这一点(即使用一些NumPy函数而不是循环)。
答案 0 :(得分:5)
这似乎做得很好:
(X.T.dot(A)*X.T).sum(axis=1)
编辑:这有点快。 np.einsum('...i,...i->...', X.T.dot(A), X.T)
。如果X
和A
是Fortran连续的话,两者都会更好。
答案 1 :(得分:3)
您可以使用numpy.einsum
:
np.einsum('ji,jk,ki->i',x,a,x)
这将得到相同的结果。让我们看看它是否更快:
看起来dot
仍然是更快的选择,特别是因为它使用线程BLAS,而不是在一个核心上运行的einsum
。
import perfplot
import numpy as np
def setup(n):
k = n
x = np.random.random((k, n))
A = np.random.random((k, k))
return x, A
def loop(data):
x, A = data
n = x.shape[1]
out = np.empty(n)
for i in range(n):
out[i] = x[:, i].T.dot(A).dot(x[:, i])
return out
def einsum(data):
x, A = data
return np.einsum('ji,jk,ki->i', x, A, x)
def dot(data):
x, A = data
return (x.T.dot(A)*x.T).sum(axis=1)
perfplot.show(
setup=setup,
kernels=[loop, einsum, dot],
n_range=[2**k for k in range(10)],
logx=True,
logy=True,
xlabel='n, k'
)
答案 2 :(得分:0)
除非你将整个事物并行化,否则你不能更快地完成它:每列一个线程。你仍然会使用循环 - 你无法摆脱它。
Map reduce是一个很好的方法来查看这个问题:map步骤倍数,减少步长。