R组合,寻找比基本R更快、更高效的方式(包、代码、并行cpu)

R组合,寻找比基本R更快、更高效的方式(包、代码、并行cpu),r,performance,matrix,combinations,R,Performance,Matrix,Combinations,我用基本R来表示组合 例如,假设我有一个2行5列的矩阵: z<-matrix(c(1, 2, 1, 3, 2, 2, 1, 3, 2, 1),nrow=2,ncol=5,byrow = TRUE) [,1] [,2] [,3] [,4] [,5] [1,] 1 2 1 3 2 [2,] 2 1 3 2 1 l<- apply(X = combn(seq_len(ncol(z)), 3),MAR = 2,FUN =

我用基本R来表示组合

例如,假设我有一个2行5列的矩阵:

 z<-matrix(c(1, 2, 1, 3, 2, 2, 1, 3, 2, 1),nrow=2,ncol=5,byrow = TRUE)

[,1] [,2] [,3] [,4] [,5]

[1,]    1    2    1    3    2

[2,]    2    1    3    2    1
l<- apply(X = combn(seq_len(ncol(z)), 3),MAR = 2,FUN = function(jj) {apply(z[, jj], 1, paste, collapse="") })
当我在矩阵中使用大数据时,问题就开始了, 例如,当我有一个15000行17列的矩阵时,我需要17列中10组的组合

在本例中,此导出需要很长时间

对于这个组合示例,有没有比基本R(可能是一些包或代码,或者使用并行cpu)更快、更有效的方法


我使用的是Windows 7 64位、FX 8320、16GB内存。

正如@inscaven所指出的,实时处理来自粘贴。如果我们只需生成所有17个choose 10组合15000次,那么随着
R
排列
RcppAlgos
中的两个高度优化的包的出现,这不会花那么长时间(我是作者):

如果我们必须将结果组合成一个字符矩阵,那么在
baser
中我们所能做的就不多了。即使我们使用上面提到的任何一个优化库,我们仍然会在所有行上循环并粘贴结果,这很慢

system.time(t1 <- lapply(1:50, function(x) {
    combn(testMat[x, ], 10, paste0, collapse = "")
}))
  user  system elapsed 
 6.847   0.070   6.933

## from package arrangements
system.time(t2 <- lapply(1:50, function(x) {
    apply(combinations(x = testMat[x, ], k = 10), 1, paste0, collapse = "")
}))
  user  system elapsed 
 6.318   0.032   6.353
此函数仅生成
v
的所有组合,选择
r
,并通过
+=
动态粘贴结果。这将生成一个向量,而无需处理矩阵的行。让我们看看有没有什么改进

numCombs <- choose(17, 10)
charMat <- matrix(as.character(testMat), nrow = 15000)

funOP <- function(z, r) {
    apply(X = combn(seq_len(ncol(z)), r), MAR = 2,FUN = function(jj) {apply(z[, jj], 1, paste, collapse="") })
}

system.time(t1 <- funOP(testMat[1:100, ], 10))
   user  system elapsed 
 22.221   0.110  22.330 

system.time(t2 <- lapply(1:100, function(x) {
     pasteCombos(17, 10, charMat[x,], numCombs)
}))
  user  system elapsed 
 7.890   0.085   7.975
现在我们正在交谈!!!快了将近12倍

这是一个健全的检查:

all.equal(t1, do.call(rbind, t2))
# [1] TRUE
all.equal(t1, do.call(rbind, t3))
# [1] TRUE

总的来说,如果我们假设我们可以在2秒钟内完成100行,我们可以在一个体面的
2*150=300秒=5分钟内完成我们的任务

不知道您可以节省多少时间,但您可以简化一点您的代码:
apply(z,1,function(x)combn(x,3,FUN=paste,collapse=”)
将产生
t(l)
。我感觉我们会看到德克过来推荐的。:)如果你还没有这样做的话,这可能是一个不错的选择。例如,你希望生成2.92亿个组合(17选择10乘以15000),因此,这需要一段时间也就不足为奇了…@nicola我建议用一些基准测试来补充这一点——我发现用一个100 x 17的矩阵选择n列,你的代码运行0.3秒,而OP的代码运行16秒。当我生成组合时,我注意到
粘贴
功能使代码变慢。以矩阵形式保存数据使代码运行效率更高
system.time(t1 <- lapply(1:50, function(x) {
    combn(testMat[x, ], 10, paste0, collapse = "")
}))
  user  system elapsed 
 6.847   0.070   6.933

## from package arrangements
system.time(t2 <- lapply(1:50, function(x) {
    apply(combinations(x = testMat[x, ], k = 10), 1, paste0, collapse = "")
}))
  user  system elapsed 
 6.318   0.032   6.353
//[[Rcpp::export]]
CharacterVector pasteCombos(int n, int r, CharacterVector v, int numRows) {

    int r1 = r - 1, r2 = r - 2;
    int numIter, count = 0;
    CharacterVector comboVec = Rcpp::no_init_vector(numRows);

    std::vector<int> z(r);
    std::iota(z.begin(), z.end(), 0);

    while (count < numRows) {
        numIter = n - z[r1];
        if ((numIter + count) > numRows)
            numIter = numRows - count;

        for (int i = 0; i < numIter; ++i, ++count, ++z[r1])
            for (int k = 0; k < r; ++k)
                comboVec[count] += v[z[k]];

        for (int i = r2; i >= 0; i--) {
            if (z[i] != (n - r + i)) {
                ++z[i];
                for (int k = (i + 1); k < r; ++k) 
                    z[k] = z[k - 1] + 1;

                break;
            }
        }
    }

    return comboVec;
}
numCombs <- choose(17, 10)
charMat <- matrix(as.character(testMat), nrow = 15000)

funOP <- function(z, r) {
    apply(X = combn(seq_len(ncol(z)), r), MAR = 2,FUN = function(jj) {apply(z[, jj], 1, paste, collapse="") })
}

system.time(t1 <- funOP(testMat[1:100, ], 10))
   user  system elapsed 
 22.221   0.110  22.330 

system.time(t2 <- lapply(1:100, function(x) {
     pasteCombos(17, 10, charMat[x,], numCombs)
}))
  user  system elapsed 
 7.890   0.085   7.975
library(parallel)
system.time(t3 <- mclapply(1:100, function(x) {
    pasteCombos(17, 10, charMat[x,], numCombs)
}, mc.cores = 8)) ## you will have to adjust this on your computer.. I'm running MacOS with 8 cores
  user  system elapsed 
 1.430   0.454   1.912
all.equal(t1, do.call(rbind, t2))
# [1] TRUE
all.equal(t1, do.call(rbind, t3))
# [1] TRUE