【问题标题】:How to bind data.table without increasing the memory consumption?如何在不增加内存消耗的情况下绑定data.table?
【发布时间】:2016-04-18 03:10:42
【问题描述】:

我几乎没有具有相同列的大型数据表dt_1, dt_2, ..., dt_N。我想将它们绑定到一个 datatable 中。如果我使用

dt <- rbind(dt_1, dt_2, ..., dt_N)

dt <- rbindlist(list(dt_1, dt_2, ..., dt_N))

那么内存使用量大约是dt_1,dt_2,...,dt_N 所需数量的两倍。有没有办法在不显着增加内存消耗的情况下绑定它们?请注意,一旦将它们组合在一起,我就不需要 dt_1, dt_2, ..., dt_N

【问题讨论】:

  • 我可能已经离开了,但是您是否考虑过在合并 dt 后从您的环境中删除 dt_1, dt_2 等?
  • 是的,我后来确实删除了它们。但是在绑定过程中,内存仍然翻了一番。
  • 查看我的答案可能会慢一些,但使用删除时绑定可能更有效的内存使用。
  • @imsc 您是通过引用询问rbind 吗?听起来很酷,不确定是否可行
  • @jangorecki。这就是我所追求的......将避免复制以及内存消耗。

标签: r data.table rbind


【解决方案1】:

我想&lt;&lt;-get 可以帮助你解决这个问题。

更新&lt;&lt;- 不是必需的。

df1 <- data.frame(x1=1:4, x2=letters[1:4], stringsAsFactors=FALSE)
df2 <- df1
df3 <- df1

dt.lst <- c("df2", "df3")

for (i in dt.lst) {
  df1 <- rbind(df1, get(i))
  rm(list=i)
}

df1

【讨论】:

    【解决方案2】:

    您可以在绑定数据表后删除它们,双重内存使用是由由副本组成的新数据框引起的。

    插图:

    #create some data
    nobs=10000
    d1 <- d2 <- d3 <-  data.table(a=rnorm(nobs),b=rnorm(nobs))
    dt <- rbindlist(list(d1,d2,d3))
    

    然后我们可以查看每个对象的内存使用情况source

    sort( sapply(ls(),function(x){object.size(get(x))}))
      nobs     d1     d2     d3     dt 
        48 161232 161232 161232 481232 
    

    如果内存使用量如此之大,单独的数据表和组合的数据表不能共存,我们可以(令人震惊,但恕我直言,这种情况是有保证的,因为数据表数量很少,而且它很容易阅读和理解)一个 for 循环和get 创建我们的组合数据表并同时删除单个数据表:

    mydts <- c("d1","d2","d3") #vector of datatable names
    
    dt<- data.table() #empty datatable to bind objects to
    
    for(d in mydts){
      dt <- rbind(dt, get(d))
      rm(list=d)
      gc() #garbage collection
    }
    

    【讨论】:

    • 也许值得澄清一下:d1 &lt;- d2 &lt;- d3 只占用内存中第一个的空间。 &lt;- DT 创建一个指向 DT 的新指针,而 &lt;- copy(DT) 将创建一个新副本(空间消耗加倍)。试试address(d1)address(d2),它们的值应该相同。 tables() 命令对于检查内存也很方便。另外,不知道为什么你会在这里get...L &lt;- list(d1,d2,d3) 可以迭代,也只是指针,我认为:sapply(L, address)
    【解决方案3】:

    其他方法,使用临时文件“绑定”:

    nobs=10000
    d1 <- d2 <- d3 <-  data.table(a=rnorm(nobs),b=rnorm(nobs))
    ll<-c('d1','d2','d3')
    tmp<-tempfile()
    
    # Write all, writing header only for the first one
    for(i in seq_along(ll)) {
      write.table(get(ll[i]),tmp,append=(i!=1),row.names=FALSE,col.names=(i==1))
    }
    
    # 'Cleanup' the original objects from memory (should be done by the gc if needed when loading the file
    rm(list=ll)
    
    # Read the file in the new object
    dt<-fread(tmp)
    
    # Remove the file
    unlink(tmp)
    

    显然比rbind 方法慢,但如果你有内存争用,这不会比要求系统换出内存页面慢。

    当然,如果您的原始对象首先是从文件加载的,那么在加载到 R 中之前,最好使用另一个最适合处理文件的工具(cat、awk 等)连接文件

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-10-29
      • 2021-03-10
      • 1970-01-01
      • 2011-06-13
      • 1970-01-01
      • 2021-10-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多