Numpy 计算;v^T A v";对于向量v的矩阵

Numpy 计算;v^T A v";对于向量v的矩阵,numpy,Numpy,我有一个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函数而不是循环)。除非将整个事情并行化:每列一个线程,否则你做

我有一个
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函数而不是循环)。

除非将整个事情并行化:每列一个线程,否则你做不到更快。你仍然会使用循环-你无法摆脱它


Map reduce是解决这个问题的一个很好的方法:映射步长倍数,减少步长和。

您可以使用
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'
    )

这似乎做得很好:
(X.T.dot(A)*X.T).和(轴=1)


编辑:这要快一点<代码>np.einsum(“…i,…i->…”,X.T.dot(A),X.T)。如果
X
A
是Fortran连续的,那么两者都能更好地工作。

当然,从复杂性的角度来看,我不能更快,但要避免Python循环(支持NumPy构造)通常通过避免较慢的Python代码来提供加速。这对于现代处理器上的大维度来说是相当慢的,因为它能够使用线程BLAS。@Ophion很好,但我相信它仍然比Python
for
循环快。。。值得检查python
for
循环cython/numpy
for
循环的东西并不重要。时间真的不在循环中。我没有线程BLAS(虽然我应该在某个时候得到它)。对于
n=10000
,这比我原来的代码(76.2ms vs.1.48ms)要好。嗯,你可能是对的。感谢
einsum
链接;很高兴知道它能做什么。可惜这不是最快的解决方案。(非常令人惊讶的是,它比@IanH在一个内核上的
n=10000,k=10
的解决方案要快)似乎轻松地击败了我的原始代码:对于
n=10000,k=10
,我的代码是76.2ms,新代码是1.64ms。美好的