使用combn()和bigmemory包生成一个非常大的字符串组合矩阵

wah*_*ulu 6 r combinatorics bigdata

我有一个1,344个独特字符串的向量x.我想生成一个矩阵,它给我所有可能的三个值组,无论顺序如何,并将其导出到csv.

我在m1.large实例w 64bit Ubuntu上运行EC on EC2.使用combn(x,3)时出现内存不足错误:

Error: cannot allocate vector of size 9.0 Gb
Run Code Online (Sandbox Code Playgroud)

得到的矩阵的大小是C1344,3 = 403,716,544行和三列 - 这是combn()函数结果的转置.

我想使用bigmemory包创建一个文件支持的big.matrix,然后我可以分配combn()函数的结果.我可以创建一个预分配的大矩阵:

library(bigmemory)
x <- as.character(1:1344)
combos <- 403716544
test <- filebacked.big.matrix(nrow = combos, ncol = 3, 
        init = 0, backingfile = "test.matrix")
Run Code Online (Sandbox Code Playgroud)

但是当我尝试分配值时,test <- combn(x, 3)我仍然会得到相同的结果:Error: cannot allocate vector of size 9.0 Gb

我甚至尝试强制结果,combn(x,3)但我认为因为combn()函数返回错误,big.matrix函数也不起作用.

test <- as.big.matrix(matrix(combn(x, 3)), backingfile = "abc")
Error: cannot allocate vector of size 9.0 Gb
Error in as.big.matrix(matrix(combn(x, 3)), backingfile = "abc") : 
  error in evaluating the argument 'x' in selecting a method for function 'as.big.matrix'
Run Code Online (Sandbox Code Playgroud)

有没有办法将这两个功能结合起来得到我需要的东西?有没有其他方法可以实现这一目标?谢谢.

Jos*_*ich 5

这是我用R编写的函数,它目前在LSPM包中找到它的(未导出的)主页.您可以为其指定项目总数n,要选择的项目数r以及所需组合的索引i; 它返回1:n与组合相对应的值i.

".combinadic" <- function(n, r, i) {

  # http://msdn.microsoft.com/en-us/library/aa289166(VS.71).aspx
  # http://en.wikipedia.org/wiki/Combinadic

  if(i < 1 | i > choose(n,r)) stop("'i' must be 0 < i <= n!/(n-r)!")

  largestV <- function(n, r, i) {
    #v <- n-1
    v <- n                                  # Adjusted for one-based indexing
    #while(choose(v,r) > i) v <- v-1
    while(choose(v,r) >= i) v <- v-1        # Adjusted for one-based indexing
    return(v)
  }

  res <- rep(NA,r)
  for(j in 1:r) {
    res[j] <- largestV(n,r,i)
    i <- i-choose(res[j],r)
    n <- res[j]
    r <- r-1
  }
  res <- res + 1
  return(res)
}
Run Code Online (Sandbox Code Playgroud)

它允许您根据词典索引的值生成每个组合:

> .combinadic(1344, 3, 1)
[1] 3 2 1
> .combinadic(1344, 3, 2)
[1] 4 2 1
> .combinadic(1344, 3, 403716544)
[1] 1344 1343 1342
Run Code Online (Sandbox Code Playgroud)

所以你只需要遍历1:403716544并将结果追加到文件中.这可能需要一段时间,但至少是可行的(参见Dirk的回答).您也可能需要在多个循环中执行此操作,因为向量1:403716544将不适合我的计算机上的内存.

或者你可以只端口将R代码,C/C++,做循环/写在那里,因为这将是一个很大更快.


Jor*_*eys 3

您可以首先找到所有 2 路组合,然后将它们与 3d 值组合,同时每次保存它们。这需要更少的内存:

combn.mod <- function(x,fname){
  tmp <- combn(x,2,simplify=F)
  n <- length(x)
  for ( i in x[-c(n,n-1)]){
    # Drop all combinations that contain value i
    id <- which(!unlist(lapply(tmp,function(t) i %in% t)))
    tmp <- tmp[id]
    # add i to all other combinations and write to file
    out <- do.call(rbind,lapply(tmp,c,i))
    write(t(out),file=fname,ncolumns=3,append=T,sep=",")
  }
}

combn.mod(x,"F:/Tmp/Test.txt")
Run Code Online (Sandbox Code Playgroud)

但这并不像约书亚的回答那么笼统,它是专门针对您的情况的。我想它更快——同样,对于这个特殊情况——但我没有进行比较。当应用于您的 x 时,该函数在我的计算机上运行,​​使用略多于 50 Mb(粗略估计)的空间。

编辑

旁注:如果这是出于模拟目的,我发现很难相信任何科学应用程序都需要 400 多万次模拟运行。您可能在这里问错误问题的正确答案......

概念验证:

我更改了写入行,在循环之前tt[[i]]<-out添加,并在循环之后添加 return(tt) 。tt <- list()然后:

> do.call(rbind,combn.mod(letters[1:5]))
      [,1] [,2] [,3]
 [1,] "b"  "c"  "a" 
 [2,] "b"  "d"  "a" 
 [3,] "b"  "e"  "a" 
 [4,] "c"  "d"  "a" 
 [5,] "c"  "e"  "a" 
 [6,] "d"  "e"  "a" 
 [7,] "c"  "d"  "b" 
 [8,] "c"  "e"  "b" 
 [9,] "d"  "e"  "b" 
[10,] "d"  "e"  "c" 
Run Code Online (Sandbox Code Playgroud)