R:如何计算矩阵行之间的相关性而不必转置它?

时间:2014-10-12 18:38:37

标签: r

我有一个大矩阵,并且对计算矩阵行之间的相关性很感兴趣。由于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值的方法。

enter image description here

如果我没有convert csmatio类进入double[][]那么C#代码运行得非常慢(数量级减慢~20-30s / file)。

3 个答案:

答案 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是矩阵的名称。