Python 如何计算3d numpy阵列的协方差矩阵?

Python 如何计算3d numpy阵列的协方差矩阵?,python,numpy,matrix,multiplication,Python,Numpy,Matrix,Multiplication,我有一个矩阵a,形状(N,D,4)。首先,我计算转置后的A,A\u t。我想计算A\u t乘以A的乘积。我希望结果矩阵的形状是(D,D),矩阵的乘积是,如果4个分量的最后一个向量是一个数字。(两个向量的点积是一个数字。) 将numpy导入为np N=15 D=98 A=np.随机.随机((N,D,4)) A_t=np.0((D,N,4)) 对于范围(N)中的i: A_t[:,i]=A[i] S=np.0((D,D)) 对于范围(D)中的i: 行=A_t[i] 对于范围(D)内的j: col=A[

我有一个矩阵
a
,形状
(N,D,4)
。首先,我计算转置后的
A
A\u t
。我想计算
A\u t
乘以
A
的乘积。我希望结果矩阵的形状是
(D,D)
,矩阵的乘积是,如果4个分量的最后一个向量是一个数字。(两个向量的点积是一个数字。)

将numpy导入为np
N=15
D=98
A=np.随机.随机((N,D,4))
A_t=np.0((D,N,4))
对于范围(N)中的i:
A_t[:,i]=A[i]
S=np.0((D,D))
对于范围(D)中的i:
行=A_t[i]
对于范围(D)内的j:
col=A[:,j,:]
val=0
对于范围内的n(n):
val+=np.matmul(行[n],列[n])
S[i][j]=val
印刷品(A.形状)
打印(A_.t.形状)
印刷品(S形)

让我们浏览一下您正在尝试的操作,看看我们可以做些什么来简化它们。首先,你可以写作

A_t = np.swapaxes(A, 0, 1)
这相当于

A_t = np.transpose(A, [0, 1, 2])

事实上,这两种方法都不是当前应用程序所必需的。要了解原因,让我们使用一个简化的示例:

np.random.seed(42)
N = 4
D = 3
K = 2
A = np.random.randint(0, 10, (N, D, K))
在外部循环中,您有
row=A\u t[i]
。但根据转置的定义,这与
row=A[:,i,:]
是相同的,这使你的生活更加轻松,而且转置是多余的

内循环对一些点积求和:

val = 0
for n in range(N):
    val += np.matmul(row[n], col[n])
如果你还记得点积的定义,你会发现你在做与点积相等的事情

np.sum(np.sum(row * col, axis=1), axis=0)
内部和是循环中的和积,而外部和是
val
的计算。对两个维度分别求和与对整个缓冲区一次求和是一样的,因此我们可以立即将内部循环替换为

for i in range(D):
    for j in range(D):
        S[i][j] = np.sum(A[:, i, :] * A[:, j, :])
您可以使用
np.dot
np.tensordot
np.einsum
,或者简单的广播来简化这个过程。前两个是不必要的复杂,因为你实际上是同时在两个维度上求和相乘
np.einsum
总体上提供了最直接的解决方案,但它是对代码的不太直接的翻译

解决方案1:广播

让我们从一个简单的双环路广播版本开始,然后再转到更惯用的解决方案:

S = (A[:, None, ...] * A[:, :, None, ...]).sum(axis=(0, -1))

这将分别创建
A
形状
(N,1,D,K)
(N,D,1,K)
的视图。在每种情况下,乘法将复制的
D
轴广播到
for
循环所做的事情,因此
N
K
轴上的最终总和与
S[i][j]=np.sum(A[:,i,:]*A[:,j,:])
行之前所做的完全相同

解决方案2:np.einsum

此解决方案允许您将和积直接应用于所需的任何轴:

S = np.einsum('ijk,ihk->jh', A, A)

请注意,您必须为第二个矩阵的第二个轴(
j
h
)使用不同的字母,以指示您不会在该轴上求和
S
是对称的,但如果不是对称的,则可以在结果中将其转置为
->hj

代码不显示您希望从矩阵中获得的内容。您可以仅使用
A\u t=A.t
进行转置。根本不需要循环。如果需要,为循环显示带有小数组和
的具体示例。预期的结果在这里很重要。代码可能不会显示它,但会显示它。我想得到A.t*A的乘积,考虑4个分量的向量,就像它们只是数字一样,所以我想要的结果矩阵是DxD。这种矩阵的值是由4个分量的两个向量的乘积得到的数字。请在代码中说明这意味着什么。您当前的代码并不构成MCVE,也没有真正为讨论提供任何有用的内容。如果必须,为
循环编写一个
。两个向量的乘积可以用多种方式定义。虽然我假设你指的是点积,但不清楚你打算如何组合这些元素来达到这一点。好吧,让我试着更清楚一点,如果我没有正确地解释我自己,我很抱歉。首先,我不能用A.T来求A的转置,因为当我这样做的时候,维度并不是我想要的三维矩阵的转置方式。我已经用循环计算了我想要的矩阵,但我想知道是否有更快更好的方法。当维度变大时,此方法太慢。感谢您发布循环。现在,100%清楚地知道你想做什么了。我很快会在Hanks上发布一个解决方案,我不知道是否应该一起问一个不同的问题,但知道矩阵S是对称的、实的和半正定的,那么获得其特征值和特征向量的最佳方法是什么?按特征值的值从大到小排序???@DanielCasasampera。这是微不足道的胡扯。我不建议在不进行基本重新搜索的情况下发布这样的问题。如果它对您有效,请不要忘记选择答案。抱歉,我不在家测试它,它符合我的要求,非常感谢您的时间!出于某种原因,在我的矩阵中,它给了我负值,有什么原因吗?
S = np.sum(A[:, None, ...] * A[:, :, None, ...], axis=(0, -1))
S = np.einsum('ijk,ihk->jh', A, A)