[英]R: How to compute correlation between rows of a matrix without having to transpose it?
我有一个很大的矩阵,并且对计算矩阵各行之间的相关性很感兴趣。 由于cor
方法计算矩阵列之间的相关性,因此我在调用cor
之前先对矩阵进行转置。 但是由于矩阵很大,因此转置非常昂贵,并且会减慢我的程序的速度。 有没有一种方法可以计算行之间的相关性而不必进行转置?
编辑 :感谢您的答复。 以为我会分享一些发现。 我的输入矩阵是16行乘以239766列,来自一个.mat文件。 我编写了C#代码,以使用csmatio
库执行相同的操作。 它看起来像这样:
foreach (var file in Directory.GetFiles(path, interictal_pattern))
{
var reader = new MatFileReader(file);
var mla = reader.Data[0] as MLStructure;
convert(mla.AllFields[0] as MLNumericArray<double>, data);
double sum = 0;
for (var i = 0; i < 16; i++)
{
for (var j = i + 1; j < 16; j++)
{
sum += cor(data, i, j);
}
}
var avg = sum / 120;
if (++count == 10)
{
var t2 = DateTime.Now;
var t = t2 - t1;
Console.WriteLine(t.TotalSeconds);
break;
}
}
static double[][] createArray(int rows, int cols)
{
var ans = new double[rows][];
for (var row = 0; row < rows; row++)
{
ans[row] = new double[cols];
}
return ans;
}
static void convert(MLNumericArray<double> mla, double[][] M)
{
var rows = M.Length;
var cols = M[0].Length;
for (int i = 0; i < rows; i++)
for (int j = 0; j < cols; j++)
M[i][j] = mla.Get(i, j);
}
static double cor(double[][] M, int i, int j)
{
var count = M[0].Length;
double sum1 = 0, sum2 = 0;
for (int ctr = 0; ctr < count; ctr++)
{
sum1 += M[i][ctr];
sum2 += M[j][ctr];
}
var mu1 = sum1 / count;
var mu2 = sum2 / count;
double numerator = 0, sumOfSquares1 = 0, sumOfSquares2 = 0;
for (int ctr = 0; ctr < count; ctr++)
{
var x = M[i][ctr] - mu1;
var y = M[j][ctr] - mu2;
numerator += x * y;
sumOfSquares1 += x * x;
sumOfSquares2 += y * y;
}
return numerator / Math.Sqrt(sumOfSquares1 * sumOfSquares2);
}
这使10个文件或22.22s /文件的吞吐量为22.22s
然后,我分析了我的R代码:
ptm=proc.time()
for(file in files)
{
i = i + 1;
mat = readMat(paste(path,file,sep=""))
a = t(mat[[1]][[1]])
C = cor(a)
correlations[i] = mean(C[lower.tri(C)])
}
print(proc.time()-ptm)
令我惊讶的是,它的运行速度比C#快,每10个文件5.7s或0.6s /文件的吞吐量(提高了近4倍 !)。 C#的瓶颈是csmatio库中用于解析输入流中双精度值的方法。
如果我不convert
csmatio类转换为double[][]
则C#代码运行极慢(数量级较慢〜20-30s /文件)。
看到此问题是由于数据输入问题引起的,该数据输入问题未说明(仅在注释中提示),因此我将假定这是一个用逗号分隔的文件,其未用引号引起来,列数= Ncol。 这会在输入上进行转置。
in.mat <- matrix( scan("path/to/the_file/fil.txt", what =numeric(0), sep=","),
ncol=Ncol, byrow=TRUE)
cor(in.nmat)
一种肮脏的解决方法是逐行应用cor-function并从结果生成相关矩阵。 您可以尝试这样做是否更有效率(我对此表示怀疑,尽管您可以通过不对所有内容进行两次重复计算或对角线多余情况进行微调):
# Apply 2-fold nested row-wise functions
set.seed(1)
dat <- matrix(rnorm(1000), nrow=10)
cormat <- apply(dat, MARGIN=1, FUN=function(z) apply(dat, MARGIN=1, FUN=function(y) cor(z, y)))
cormat[1:3,1:3] # Show few first
# [,1] [,2] [,3]
#[1,] 1.000000000 0.002175792 0.1559263
#[2,] 0.002175792 1.000000000 -0.1870054
#[3,] 0.155926259 -0.187005418 1.0000000
虽然,一般而言,我希望转置具有一个非常非常有效的实现,所以很难想象何时会成为瓶颈。 但是,您还可以通过首先确保您的行合适来深入研究“ cor”函数的实现,并调用相关C函数本身。 在终端中键入“ cor”以查看实现,该实现主要是一个包装程序,使输入适合于C函数:
# Row with C-call from the implementation of 'cor':
# if (method == "pearson")
# .Call(C_cor, x, y, na.method, FALSE)
您可以使用outer
:
outer(seq(nrow(mat)), seq(nrow(mat)),
Vectorize(function(x, y) cor(mat[x , ], mat[y , ])))
mat
是矩阵的名称。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.