【问题标题】:Converting all data.frames in environment to data.tables将环境中的所有 data.frames 转换为 data.tables
【发布时间】:2019-12-07 15:05:06
【问题描述】:

我在将所有 data.frames 转换为 data.tables 后立即使用 := 时收到警告:

library(data.table) #Win R-3.5.1 x64 data.table_1.12.2
df1 <- data.frame(A=1, B=2)
df2 <- data.frame(D=3)
lapply(mget(ls()), function(x) {
    if (is.data.frame(x)) {
        setDT(x)
    }
})
df1[, rn:=.I]

警告信息: 在[.data.table(df1, , :=(rn, .I)) 中: 通过获取 data.table 的(浅)副本检测和修复无效的 .internal.selfref ,以便 := 可以通过引用添加此新列。在较早的时候,这个 data.table 已被 R 复制(或使用 structure() 或类似方法手动创建)。避免 names

下面也会产生同样的警告:

df3 <- data.frame(E=3)
df4 <- data.frame(FF=4)
for (l in list(df3, df4)) setDT(l)
df3[, rn:=.I]

一个一个地打字很有效,但是很乏味

df5 <- data.frame(G=5)
setDT(df5)
df[, rn := .I]    #no warning

将所有data.frames转换为data.tables的惯用方法是什么?

相关:

  1. Using setDT inside a function
  2. Invalid .internal.selfref in data.table

【问题讨论】:

    标签: r data.table


    【解决方案1】:

    这应该可以解决问题:

    library(data.table) #Win R-3.5.1 x64 data.table_1.12.2
    df1 <- data.frame(A=1, B=2)
    df2 <- data.frame(D=3)
    for (x in ls()) {
        if (is.data.frame(get(x))) {
            assign(x, as.data.table(get(x)))
        }
    }
    df1[, rn:=.I]
    

    我猜(虽然不确定)for/lapply 循环使用了一种自己的环境,它与data.table 的 by ref 语义相混淆。

    【讨论】:

    • thks thothal。如果除了assignas.data.table 之外没有出现,我将等待 24 小时后再接受您的回答
    • 谢谢你。由于速度和内存使用情况,我选择了另一个作为答案
    【解决方案2】:

    setDT 对名称/符号进行操作,而get 返回对象的值。您可以构造 setDT 表达式并对其求值:

    library(data.table) 
    df1 <- data.frame(A=1, B=2)
    df2 <- data.frame(D=3)
    for(x in ls()){
      if (is.data.frame(get(x))) {
        eval(substitute(setDT(x), list(x=as.name(x))))
      }
    }
    rm(x)
    df1[, rn:=.I]
    

    我会使用循环而不是 lapply 来避免复杂化(例如,使用评估环境)。

    【讨论】:

      【解决方案3】:

      有点晚了,但这似乎是一个很好的——而且很少见的——使用eapply()(以及list2env())。当然,这是另一种选择,当然不是说它是惯用的方式。

      library(data.table)
      df1 <- data.frame(A=1, B=2)
      df2 <- data.frame(D=3)
      
      list2env(eapply(.GlobalEnv, function(x) {if(is.data.frame(x)) {setDT(x)} else {x}}), .GlobalEnv)
      
      df1[, rn:=.I]
      df1
         A B rn
      1: 1 2  1
      

      一些时间和内存使用情况:

      set.seed(0L)
      sz <- 1e7
      df1 <- data.frame(A=rnorm(sz))
      df2 <- data.frame(B=rnorm(sz))
      df3 <- copy(df1)
      df4 <- copy(df2)
      
      microbenchmark::microbenchmark(unit="ms", times=1L,
          assign_mtd = {
              for (x in ls()) {
                  if (is.data.frame(get(x))) {
                      assign(x, as.data.table(get(x)))
                  }
              }
          },
          eval_sub_mtd = {
              for(x in ls()){
                  if (is.data.frame(get(x))) {
                      eval(substitute(setDT(x), list(x=as.name(x))))
                  }
              }
          },
          eapply_mtd = {
              list2env(eapply(.GlobalEnv, function(x) {
                      if (is.data.frame(x)) setDT(x) else x
                  }), .GlobalEnv)
          }
      )
      

      时间安排:

      Unit: milliseconds
               expr        min         lq       mean     median         uq        max neval
         assign_mtd 115.922802 115.922802 115.922802 115.922802 115.922802 115.922802     1
       eval_sub_mtd   3.293358   3.293358   3.293358   3.293358   3.293358   3.293358     1
         eapply_mtd   1.913802   1.913802   1.913802   1.913802   1.913802   1.913802     1
      

      【讨论】:

      • @Frank 和 Andrew,我不确定更改标记解决方案的礼仪。由于这更快,我想改为改为这个答案。可以吗?
      • 酷加速!我不认为我曾经使用过 eapply,我猜如果周围有很多其他对象,else x 可能会很昂贵(不确定)? @chinsoon12 听起来不错,np。顺便说一句,我不会在@看到你的消息——我只是在看到你在我的帖子上的编辑后浏览了这里。
      猜你喜欢
      • 2016-05-25
      • 2018-05-31
      • 1970-01-01
      • 2019-08-27
      • 2016-11-22
      • 2016-08-23
      • 1970-01-01
      • 2019-12-18
      • 1970-01-01
      相关资源
      最近更新 更多