【问题标题】:Generating a very large matrix of string combinations using combn() and bigmemory package使用 combn() 和 bigmemory 包生成一个非常大的字符串组合矩阵
【发布时间】:2011-05-28 10:56:12
【问题描述】:

我有一个包含 1,344 个唯一字符串的向量 x。我想生成一个矩阵,它为我提供所有可能的三个值组,无论顺序如何,并将其导出到 csv。

我在带有 64 位 Ubuntu 的 m1.large 实例上的 EC2 上运行 R。使用 combn(x, 3) 时出现内存不足错误:

Error: cannot allocate vector of size 9.0 Gb

结果矩阵的大小为 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")

但是当我尝试分配值 test &lt;- 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'

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

【问题讨论】:

  • 您是否考虑过使用combinadics 来生成每个组合?我想我有一些 R 代码可以做到这一点,但我必须挖掘它。
  • @Josh 我不确定我是否理解组合学与我想要实现的目标有何不同。我以 as.character(1:1344) 为例,但实际情况是我的值不是连续的。如果您认为您拥有的 R 代码可能会有所帮助,请发布。谢谢!
  • @Joshua @Joris @Dirk 感谢您的所有建议。由于时间限制,我选择了 Joris 的方法(尽管我不知道哪个更快)。我让系统在所有 400m 线路上运行一段时间。 @Joshua,我认为很多人会在您的组合函数中发现很多价值。

标签: r combinatorics bigdata


【解决方案1】:

这是我用 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)
}

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

> .combinadic(1344, 3, 1)
[1] 3 2 1
> .combinadic(1344, 3, 2)
[1] 4 2 1
> .combinadic(1344, 3, 403716544)
[1] 1344 1343 1342

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

或者您可以将 R 代码移植到 C/C++ 并在那里进行循环/编写,因为它会快很多

【讨论】:

  • 谢谢乔希。我会试一试,然后告诉你它是如何工作的。
  • 可爱的实现!我必须仔细看看它是如何工作的,但它肯定是一颗宝石。
  • @Joris 感谢 James McCaffrey。我在 MSDN 上找到了实现。老实说,我花了几天的时间来围绕它和 LSPM 中其他未导出的组合函数(也来自 MSDN)。
  • 伟大的工作,对于任何试图了解如何使其与字符串一起工作的人,您需要计算n0 &lt;- length(n),并将任何n替换为n0,最后使用n[res]获得这种组合的值。
  • 另外,如果使用它来填充距离矩阵,它基本上是按列返回上三角距离矩阵的值
【解决方案2】:

您可以先找到所有 2-way 组合,然后将它们与 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")

虽然这不像 Joshua 的回答那样笼统,但它专门针对您的情况。我想它更快 - 再次,对于这种特殊情况 - 但我没有进行比较。当应用到您的 x 时,该函数在我的计算机上使用略高于 50 Mb(粗略估计)运行。

编辑

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

概念证明:

我将写入行更改为tt[[i]]&lt;-out,在循环之前添加tt &lt;- list(),并在循环之后添加return(tt)。那么:

> 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" 

【讨论】:

    【解决方案3】:

    第一个近似值,每个算法都会牺牲存储来换取速度。

    您在尝试预分配完全枚举的组合矩阵时遇到了问题。所以也许你不应该尝试预先分配这个矩阵,而是尝试说,

    1. 如果您认为需要这些组合,请在其他地方计算它们并将它们存储在一个简单的数据库(或者,哎呀,平面文件)中并查找它们——节省了 9 GB

    2. 利用开源,将代码阅读到combn() 并将其修改为客户端-服务器的东西:给定一个索引号为N的调用,它将循环并返回 Nth 条目。效率不高,但可能更容易可行

    【讨论】:

    • 我不想将矩阵保存在内存中,也不想在 R 中对它做任何事情。我只想生成值并创建一个平面文件,然后将其作为输入一个 mapreduce 工作,只要每条线是我正在运行的模拟的一个独特案例。我想查看 combn() 的代码并可能修改它以使用 big.matrix,但我只是没有时间。当您建议在其他地方(以上 1)计算它们时,您会推荐什么?
    • 你甚至可以自己做 R:获取函数,但不是将它们写入一个大矩阵,而是逐步写入文件或数据库。
    猜你喜欢
    • 1970-01-01
    • 2018-08-01
    • 1970-01-01
    • 2018-09-07
    • 1970-01-01
    • 2023-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多