【问题标题】:How to vectorize comparing each row of matrix with all other rows如何矢量化将矩阵的每一行与所有其他行进行比较
【发布时间】:2014-01-18 19:36:01
【问题描述】:

我正在尝试将每一行与矩阵中的所有其他行进行比较,以计算每行与所有其他行的差异数。然后将结果存储在矩阵的左下角三角形中。

例如,当行 m[1,] 与行 m[2,] 和 m[3,] 进行比较时,差异计数存储在结果中 mat[c(2:3), 1] 的位置矩阵。

我的问题是我的输入矩阵最多可以有 1e+07 行,并且当前的实现(速度和内存)由于 n^2 比较而无法扩展。建议和帮助将不胜感激。

diffMatrix <- function(x) {

  rows <- dim(x)[1] #num of rows
  cols <- dim(x)[2] #num of columns

  if (rows <= 1) stop("'x' must have atleast two rows")

  #potential failure point
  mat <- matrix(, rows, rows)

  # fill bottom left triangle columns ignoring the diagonal
  for (row in 1:(rows-1)) { 
    rRange <- c((1+row):rows)
    m <- matrix(x[row,], nrow=rows-row, ncol=cols, byrow = T)
    mat[rRange, row] <- rowSums(m != x[-1:-row, ])
  }

  return (mat)
}   


m <- matrix(sample(1:12, 12, replace=T), ncol=2, byrow=TRUE)
m
#     [,1] [,2]
#[1,]    8    1
#[2,]    4    1
#[3,]    8    4
#[4,]    4    5
#[5,]    3    1
#[6,]    2    2

x <- diffMatrix(m)
x
#     [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]   NA   NA   NA   NA   NA   NA
#[2,]    1   NA   NA   NA   NA   NA
#[3,]    1    2   NA   NA   NA   NA
#[4,]    2    1    2   NA   NA   NA
#[5,]    1    1    2    2   NA   NA
#[6,]    2    2    2    2    2   NA

m <- matrix(sample(1:5, 50000, replace=T), ncol=10, byrow=TRUE)
# system.time(x <- diffMatrix(m))
#   user  system elapsed 
#  20.39    0.38   21.43 

【问题讨论】:

  • 你有多少内存?您可能不得不求助于将结果写入磁盘。
  • 自定义客户端应用程序是 R 服务器池上的前端并发请求。每个请求都在调用 diffMatrix 需要参与的 R 函数。因此,低内存和超高速至关重要。
  • 无论您怎么看,您都必须计算和存储n^2 比较。除非您可以预先计算此矩阵并将其存储以供客户稍后查找,否则您所要求的实际上是不可能的。
  • 是的,但是应该有一些方法可以混合 expand.grid 的想法 (stackoverflow.com/questions/19933788/…) 和我的半行循环方法。明天我会试试@alexis_laz 的推荐。
  • 您可以根据矩阵包含的数据类型来偷工减料:浮点数、整数、有限范围内的整数、逻辑或其他?稀疏吗?

标签: r loops matrix vectorization


【解决方案1】:

这是使用.Call 的替代方法(似乎有效,但我不能保证):

library(inline)

ff = cfunction(sig = c(R_mat = "matrix"), body = '
SEXP mat, dims, ans, dimans;

PROTECT(dims = getAttrib(R_mat, R_DimSymbol));
PROTECT(dimans = allocVector(INTSXP, 2));
R_len_t *pdims = INTEGER(dims), *pdimans = INTEGER(dimans);
PROTECT(ans = allocVector(INTSXP, pdims[0]*pdims[0]));
R_len_t *pans = INTEGER(ans);
pdimans[0] = pdims[0];
pdimans[1] = pdims[0];

for(int ina = 0; ina < LENGTH(ans); ina++) {
   pans[ina] = NA_INTEGER;
}

switch(TYPEOF(R_mat)) {
   case REALSXP:
   {
    PROTECT(mat = coerceVector(R_mat, REALSXP));
    double *pmat = REAL(mat);
    for(int i = 0; i < pdims[0]; i++) {
       R_len_t ir;
       for(ir = i+1; ir < pdims[0]; ir++) {
          R_len_t diffs = 0;
          for(int ic = 0; ic < pdims[1]; ic++) {
             if(pmat[i + ic*pdims[0]] != pmat[ir + ic*pdims[0]]) {
               diffs++;
             }
          }
          pans[ir + i*pdims[0]] = diffs;
       }
    }
    break;
   }

   case INTSXP:
   {
    PROTECT(mat = coerceVector(R_mat, INTSXP));
    R_len_t *pmat = INTEGER(mat);
    for(int i = 0; i < pdims[0]; i++) {
       R_len_t ir; 
       for(ir = i+1; ir < pdims[0]; ir++) {
          R_len_t diffs = 0;
          for(int ic = 0; ic < pdims[1]; ic++) {
             if(pmat[i + ic*pdims[0]] != pmat[ir + ic*pdims[0]]) {
               diffs++;
             }
          }
          pans[ir + i*pdims[0]] = diffs;
       }
    }
    break;
   }
}

setAttrib(ans, R_DimSymbol, dimans);

UNPROTECT(4);

return(ans);
')

m = matrix(c(8,4,8,4,3,2,1,1,4,5,1,2), ncol = 2)
ff(m)
#     [,1] [,2] [,3] [,4] [,5] [,6]
#[1,]   NA   NA   NA   NA   NA   NA
#[2,]    1   NA   NA   NA   NA   NA
#[3,]    1    2   NA   NA   NA   NA
#[4,]    2    1    2   NA   NA   NA
#[5,]    1    1    2    2   NA   NA
#[6,]    2    2    2    2    2   NA
all.equal(diffMatrix(m), ff(m))
#[1] TRUE

m2 <- matrix(sample(1:5, 50000, replace=T), ncol=10, byrow=TRUE)
library(microbenchmark)
microbenchmark(diffMatrix(m2), ff(m2), times = 10)
#Unit: milliseconds
#           expr       min        lq   median        uq        max neval
# diffMatrix(m2) 6972.9778 7049.3455 7427.807 7633.7581 11337.3154    10
#         ff(m2)  422.3195  469.5771  530.470  661.8299   862.3092    10
all.equal(diffMatrix(m2), ff(m2))
#[1] TRUE

【讨论】:

  • 如果您要走C 路线,我强烈建议您查看Rcpp。它提供了大量语法糖,使底层 C 语言更容易编写。
  • @ScottRitchie:“Rcpp”在我 2014 年的“待办事项”清单上! :-)
猜你喜欢
  • 1970-01-01
  • 2017-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多