我有一个大矩阵,并且对计算矩阵行之间的相关性很感兴趣。由于cor
方法计算矩阵列之间的相关性,因此我在调用cor
之前调换矩阵。但由于矩阵很大,转置它是昂贵的,并且正在减慢我的程序。有没有办法计算行之间的相关性而不必采取转置?
编辑:感谢您的回复。我以为我会分享一些调查结果。我的输入矩阵是16行乘239766列,来自.mat文件。我使用csmatio
库编写了C#代码来做同样的事情。它看起来像这样:
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.22秒的吞吐量或 2.22s / file
然后我描述了我的 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 / file (几乎 4x 的改进!)。 C#中的瓶颈是csmatio库中用于解析输入流中的double值的方法。
如果我没有convert
csmatio类进入double[][]
那么C#代码运行得非常慢(数量级减慢~20-30s / file)。
答案 0 :(得分:4)
看到这个问题是由数据输入问题引起的,其细节没有说明(并且只在评论中暗示),我将假设这是一个逗号分隔的文件,其中包含列数= Ncol的未加引号的数字。这会对输入进行转置。
in.mat <- matrix( scan("path/to/the_file/fil.txt", what =numeric(0), sep=","),
ncol=Ncol, byrow=TRUE)
cor(in.nmat)
答案 1 :(得分:2)
一个肮脏的解决方法是逐行应用cor-functions并从结果中生成相关矩阵。你可以试试这是否更有效(我怀疑,虽然你可以通过不计算所有内容或冗余对角线情况来微调它):
# 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)
答案 2 :(得分:1)
您可以使用outer
:
outer(seq(nrow(mat)), seq(nrow(mat)),
Vectorize(function(x, y) cor(mat[x , ], mat[y , ])))
其中mat
是矩阵的名称。