使用来自R中的两个(稀疏)矩阵的数据构建“签名矩阵”的效率问题

时间:2012-10-17 14:48:30

标签: performance r matrix sparse-matrix

我不知道我尝试构建的“签名矩阵”是否在任何字段中都有适当的预先存在的名称或定义,但以下代码似乎可以在某些玩具矩阵中生成正确的结果。我无法解释我究竟想要做什么而不会造成混淆,但如果我提供的代码不足以推断出我想要做的事情,我很乐意尝试一下。

当我使用我的实际数据运行此代码时(两个整数矩阵大小约为300 x 20,000个元素),它似乎正在工作,但在数小时和数小时之后它仍然无法完成。

我知道迭代可能是这里最大的问题,但我还没有弄清楚如何删除它。

代码:

# Load required library
library(Matrix)

# Load in the test data
mut <- matrix(data=c(1,1,1,0,0,0,0,1,0,1,1,0,0,1,1,0,0,0,1,0),
              nrow=5,ncol=4,
              dimnames=list(c("p1","p2","p3","p4","p5"),c("GA","GB","GC","GD")))

oute <- matrix(data=c(1,1,0,1,0,1,0,0,1,1,1,1,1,0,0,1,1,0,0,1),
              nrow=5,ncol=4,
              dimnames=list(c("p1","p2","p3","p4","p5"),c("GQ","GW","GE","GR")))

patOutMatrix <- Matrix(data=oute,sparse=TRUE)
patMutMatrix <- Matrix(data=mut,sparse=TRUE)

transposePatMutMatrix <- t(patMutMatrix)

# Build the empty matrix (with row and col names)
sigMatrix <- Matrix(0,nrow=ncol(patMutMatrix), ncol=ncol(patOutMatrix),sparse=TRUE)
rownames(sigMatrix) <- colnames(patMutMatrix)
colnames(sigMatrix) <- colnames(patOutMatrix)

# Populate sigMatrix
for (mgene in rownames(transposePatMutMatrix))
{
  a <- patOutMatrix[which(transposePatMutMatrix[mgene, ] == 1, arr.ind = T), ]

  # Using an IF here to get around a problem with colSums() not working on single rows
  sigMatrix[mgene,] <- if (dim(as.matrix(a))[2] == 1) {
    a
  } else {
    colSums(patOutMatrix[which(transposePatMutMatrix[mgene, ] == 1, arr.ind = T), ])
  }
}

有谁知道如何在这里改变任何东西以使其表现更快?

1 个答案:

答案 0 :(得分:0)

如何对计算进行矢量化

看起来你只是在那里计算matrix product。所以这样写:

sigMatrix <- t(patMutMatrix) %*% patOutMatrix

或(更难阅读但性能更好):

sigMatrix <- crossprod(patMutMatrix, patOutMatrix)

代码的作用

假设您的矩阵只有0和1个条目,则代码执行以下操作:从第一个列中的一个列和第二个矩阵中的一个列中获取每个可能的组合,它计算在两个矩阵中都有1的行数。这些专栏。对于您的示例数据,这会得到以下结果:

> patMutMatrix   > patOutMatrix   > sigMatrix
   GA GB GC GD      GQ GW GE GR      GQ GW GE GR
p1  1  .  1  .   p1  1  1  1  1   GA  2  1  3  2
p2  1  .  .  .   p2  1  .  1  1   GB  .  1  1  1
p3  1  1  .  .   p3  .  .  1  .   GC  2  3  1  2
p4  .  .  1  1   p4  1  1  .  .   GD  1  1  .  .
p5  .  1  1  .   p5  .  1  .  1

如果矩阵不限于0和1,那么我的代码会做一些与你的代码不同的代码,就像你处理除1之外的任何值的第一个矩阵一样。

从中学习的其他事项

避免案例区分

  # Using an IF here to get around a problem with colSums() not working on single rows

您可以通过将drop = FALSE传递给子集操作来避免这种情况,如下所示:

patOutMatrix[which(transposePatMutMatrix[mgene, ] == 1, arr.ind = T), , drop = FALSE]

这样,子集操作的结果总是是一个矩阵,即使该矩阵只有一行。

避免按名称访问

for (mgene in rownames(transposePatMutMatrix))

通常最好迭代索引而不是名称,因为按名称选择内容会导致一次额外的查找将该名称转换回索引。所以我宁愿做这个

for (mgene in 1:nrow(transposePatMutMatrix))