MATLAB:从该数据计算协方差矩阵的有效方法
MATLAB: Efficient way to calculate a covariance matrix from this data
我有一个数据文件,其中有 N=428 个受试者,每个受试者回答相同的 8 个问题。它看起来像这样:
question subject score
1 1 42
2 1 12
3 1 13
4 1 43
5 1 22
6 1 43
7 1 54
8 1 66
1 2 41
2 2 11
... ... ...
我想计算并存储一个反映每个科目分数的协方差矩阵。
因此单元格 (1,1) 具有主题 1 的方差。那么单元格 (1,2) 和 (2,1) 都将具有相同的值,即主题 1 和主题 2 之间的协方差。虽然在上面的 table 中你看不到主题 2 的所有数据,看起来他们与主题 1 有一些正协方差。
n choose k 必须计算唯一协方差,我计算出总共是 91378。
我怎样才能有效地实现这一点?
编辑:使用来自@GameOfThrows 的代码,我能够使用循环获得一个工作版本:
crowd_cov = NaN(428,428);
for i = 1:length(allpairs)
Z = cov(score(indexSub1(i,1):indexSub1(i,2)),score(indexSub2(i,1):indexSub2(i,2)));
first = allpairs(i,1);
second = allpairs(i,2);
crowd_cov(first,first) = Z(1,1);
crowd_cov(second,second) = Z(2,2);
crowd_cov(first,second) = Z(1,2);
crowd_cov(second,first) = Z(2,1);
end
我对此很满意,尽管我仍然欢迎解释我如何更有效地编写代码。
所以你想要协方差,它告诉我你有两个随机变量,比如科目 1 的分数和科目 2 的分数,现在我们希望问题列不会在其中发挥重要作用,但是如果每个主题的问题数量相同,那么它将极大地提高程序的效率(因为它允许快速索引)。
allpairs = combnk(1:max(subject),2) %// all possible combinations of subjects starting from subject 1 to subject N and the 2 means you want pairs.
现在请注意,这没有重复,因此 sub 1 vs sub 2 只发生一次,sub 2 vs sub 1 不存在。
现在你想对每对做 matlab cov(你需要正确索引分数)。这是如果你有相同数量的问题,它会节省你很多时间,每个主题说8个问题:
indexSub1 = [(allpairs(:,1)*8 -7),(allpairs(:,1)*8)]
indexSub2 = [(allpairs(:,2)*8 -7),(allpairs(:,2)*8)]
现在你有了所有正确的索引,你可以使用cov;作为函数,将其应用于
的每 8 个元素
cov(score(indexSub1),score(indexSub2)).
如果问题的数量不一样,那么您可能必须使用 find 来正确索引,这会降低您的程序速度。
最后,您可以将矩阵转换为单元格并使用 cellfun 来应用 cov,或者您可以使用循环来进行更简单的表示(我建议使用循环吗?不)。
编辑:
澄清一下,我的建议是你有 indexSub1 和 indexSub2,你可以将它们转换成 91378*2 个单元格,每个单元格包含 8 个分数。这将允许您使用 Matlab 的 cellfun(其中一个函数应用于每个单元格)。这将大大提高您的速度。
我有一个数据文件,其中有 N=428 个受试者,每个受试者回答相同的 8 个问题。它看起来像这样:
question subject score
1 1 42
2 1 12
3 1 13
4 1 43
5 1 22
6 1 43
7 1 54
8 1 66
1 2 41
2 2 11
... ... ...
我想计算并存储一个反映每个科目分数的协方差矩阵。
因此单元格 (1,1) 具有主题 1 的方差。那么单元格 (1,2) 和 (2,1) 都将具有相同的值,即主题 1 和主题 2 之间的协方差。虽然在上面的 table 中你看不到主题 2 的所有数据,看起来他们与主题 1 有一些正协方差。
n choose k 必须计算唯一协方差,我计算出总共是 91378。
我怎样才能有效地实现这一点?
编辑:使用来自@GameOfThrows 的代码,我能够使用循环获得一个工作版本:
crowd_cov = NaN(428,428);
for i = 1:length(allpairs)
Z = cov(score(indexSub1(i,1):indexSub1(i,2)),score(indexSub2(i,1):indexSub2(i,2)));
first = allpairs(i,1);
second = allpairs(i,2);
crowd_cov(first,first) = Z(1,1);
crowd_cov(second,second) = Z(2,2);
crowd_cov(first,second) = Z(1,2);
crowd_cov(second,first) = Z(2,1);
end
我对此很满意,尽管我仍然欢迎解释我如何更有效地编写代码。
所以你想要协方差,它告诉我你有两个随机变量,比如科目 1 的分数和科目 2 的分数,现在我们希望问题列不会在其中发挥重要作用,但是如果每个主题的问题数量相同,那么它将极大地提高程序的效率(因为它允许快速索引)。
allpairs = combnk(1:max(subject),2) %// all possible combinations of subjects starting from subject 1 to subject N and the 2 means you want pairs.
现在请注意,这没有重复,因此 sub 1 vs sub 2 只发生一次,sub 2 vs sub 1 不存在。
现在你想对每对做 matlab cov(你需要正确索引分数)。这是如果你有相同数量的问题,它会节省你很多时间,每个主题说8个问题:
indexSub1 = [(allpairs(:,1)*8 -7),(allpairs(:,1)*8)]
indexSub2 = [(allpairs(:,2)*8 -7),(allpairs(:,2)*8)]
现在你有了所有正确的索引,你可以使用cov;作为函数,将其应用于
的每 8 个元素cov(score(indexSub1),score(indexSub2)).
如果问题的数量不一样,那么您可能必须使用 find 来正确索引,这会降低您的程序速度。
最后,您可以将矩阵转换为单元格并使用 cellfun 来应用 cov,或者您可以使用循环来进行更简单的表示(我建议使用循环吗?不)。
编辑:
澄清一下,我的建议是你有 indexSub1 和 indexSub2,你可以将它们转换成 91378*2 个单元格,每个单元格包含 8 个分数。这将允许您使用 Matlab 的 cellfun(其中一个函数应用于每个单元格)。这将大大提高您的速度。