4

如果没有在具有更多 RAM 的机器上工作,我该如何处理 中的大型列表R,例如将它们放在磁盘上,然后处理其中的部分?

这是一些生成我正在使用的列表类型的代码

n = 50; i = 100
WORD <- vector(mode = "integer", length = n)
for (i in 1:n){
  WORD[i] <- paste(sample(c(rep(0:9,each=5),LETTERS,letters),5,replace=TRUE),collapse='')
}
dat <- data.frame(WORD =  WORD,
                  COUNTS = sample(1:50, n, replace = TRUE))
dat_list <- lapply(1:i, function(i) dat) 

在我的实际用例中,列表中的每个数据框都是唯一的,与此处的快速示例不同。我的目标是 n = 4000 和 i = 100,000

这是我想用这个数据框列表做的一个例子:

FUNC <- function(x) {rep(x$WORD, times = x$COUNTS)}
la <- lapply(dat_list, FUNC)

在我的实际用例中,它运行了几个小时,填满了 RAM 和大部分交换,然后 RStudio 冻结并显示一条带有炸弹的消息(由于 R 会话中的错误,RStudio 被迫终止)。

我看到这bigmemory仅限于矩阵并且ff似乎无法处理列表。还有哪些其他选择?如果sqldf此处可能存在相关的内存不足方法,我该如何开始?我无法从文档中获得足够的进展来取得任何进展,并会感谢任何指示。请注意,“购买更多 RAM”的说明将被忽略!这是一个我希望适合普通台式计算机(即本科计算机实验室)的软件包。

更新跟进 SimonO101 和 Ari 的有用评论,这里有一些比较数据帧和 data.tables、循环和 lapply 以及有和没有 gc 的基准测试

# self-contained speed test of untable
n = 50; i = 100
WORD <- vector(mode = "integer", length = n)
for (i in 1:n){
  WORD[i] <- paste(sample(c(rep(0:9,each=5),LETTERS,letters),5,replace=TRUE),collapse='')
}
# as data table
library(data.table)
dat_dt <- data.table(WORD = WORD, COUNTS = sample(1:50, n, replace = TRUE))
dat_list_dt <- lapply(1:i, function(i) dat_dt)

# as data frame
dat_df <- data.frame(WORD =  WORD, COUNTS = sample(1:50, n, replace = TRUE))
dat_list_df <- lapply(1:i, function(i) dat_df)

# increase object size
y <- 10
dt <- c(rep(dat_list_dt, y))
df <- c(rep(dat_list_df, y))
# untable
untable <- function(x) rep(x$WORD, times = x$COUNTS)


# preallocate objects for loop to fill
df1 <- vector("list", length = length(df))
dt1 <- vector("list", length = length(dt))
df3 <- vector("list", length = length(df))
dt3 <- vector("list", length = length(dt))
# functions for lapply
df_untable_gc <- function(x) { untable(df[[x]]); if (x%%10) invisible(gc()) }
dt_untable_gc <- function(x) { untable(dt[[x]]); if (x%%10) invisible(gc()) }
# speedtests
library(microbenchmark)
microbenchmark(
  for(i in 1:length(df)) { df1[[i]] <- untable(df[[i]]); if (i%%10) invisible(gc()) },
  for(i in 1:length(dt)) { dt1[[i]] <- untable(dt[[i]]); if (i%%10) invisible(gc()) },
  df2 <- lapply(1:length(df), function(i) df_untable_gc(i)),
  dt2 <- lapply(1:length(dt), function(i) dt_untable_gc(i)),
  for(i in 1:length(df)) { df3[[i]] <- untable(df[[i]])},
  for(i in 1:length(dt)) { dt3[[i]] <- untable(dt[[i]])},
  df4 <- lapply(1:length(df), function(i) untable(df[[i]]) ),
  dt4 <- lapply(1:length(dt), function(i) untable(dt[[i]]) ),

  times = 10)

这是结果,没有显式垃圾收集,data.table 比循环快得多,并且 lapply 略快。使用显式垃圾收集(我认为 SimonO101 可能会暗示)它们的速度几乎相同 - 慢得多!我知道 usinggc有点争议,在这种情况下可能没有帮助,但我会用我的实际用例试一试,看看它是否有什么不同。当然,我没有任何这些函数的内存使用数据,这确实是我主要关心的问题。似乎没有与计时功能等效的内存基准测试功能(无论如何,对于 Windows)。

Unit: milliseconds
                                                                                                 expr
 for (i in 1:length(df)) {     df1[[i]] <- untable(df[[i]])     if (i%%10)          invisible(gc()) }
 for (i in 1:length(dt)) {     dt1[[i]] <- untable(dt[[i]])     if (i%%10)          invisible(gc()) }
                                            df2 <- lapply(1:length(df), function(i) df_untable_gc(i))
                                            dt2 <- lapply(1:length(dt), function(i) dt_untable_gc(i))
                                         for (i in 1:length(df)) {     df3[[i]] <- untable(df[[i]]) }
                                         for (i in 1:length(dt)) {     dt3[[i]] <- untable(dt[[i]]) }
                                            df4 <- lapply(1:length(df), function(i) untable(df[[i]]))
                                            dt4 <- lapply(1:length(dt), function(i) untable(dt[[i]]))
          min           lq       median           uq         max neval
 37436.433962 37955.714144 38663.120340 39142.350799 39651.88118    10
 37354.456809 38493.268121 38636.424561 38914.726388 39111.20439    10
 36959.630896 37924.878498 38314.428435 38636.894810 39537.31465    10
 36917.765453 37735.186358 38106.134494 38563.217919 38751.71627    10
    28.200943    29.221901    30.205502    31.616041    34.32218    10
    10.230519    10.418947    10.665668    12.194847    14.58611    10
    26.058039    27.103217    27.560739    28.189448    30.62751    10
     8.835168     8.904956     9.214692     9.485018    12.93788    10
4

1 回答 1

1

如果你真的要使用非常大的数据,你可以使用 h5r 包来编写 hdf5 文件。您将即时写入和读取硬盘驱动器,而不是使用 RAM。我没有用过这个,所以我对它的一般用法没什么帮助,我提到这个是因为我认为没有教程。我通过考虑 pytables 得到了这个想法。不确定此解决方案是否适合您。

于 2013-05-19T18:42:30.297 回答