将环境中的所有 data.frames 转换为 data.tables

chi*_*n12 6 r data.table

:=在将所有 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]
Run Code Online (Sandbox Code Playgroud)

警告消息: In [.data.table(df1, , :=(rn, .I)) : Invalid .internal.selfref 通过获取 data.table 的(浅)副本检测和修复,以便 := 可以通过引用添加此新列。早些时候,这个 data.table 已被 R 复制(或使用 structure() 或类似方法手动创建)。避免 names<- 和 attr<- 目前在 R 中(而且很奇怪)可能会复制整个 data.table。使用 set* 语法来避免复制:?set、?setnames 和 ?setattr。如果此消息没有帮助,请将您的用例报告给 data.table 问题跟踪器,以便修复根本原因或改进此消息。

下面也生成相同的警告:

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

一项一项的打字有效但乏味

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

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

有关的:

  1. 在函数内使用 setDT
  2. data.table 中的 .internal.selfref 无效

Fra*_*ank 5

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]
Run Code Online (Sandbox Code Playgroud)

我会使用循环而不是lapply避免并发症(例如,使用评估环境)。


And*_*rew 3

有点晚了,但这似乎是一个很棒的\xe2\x80\x94和罕见的\xe2\x80\x94用途eapply()(以及list2env())。当然,这是另一种选择,当然不是断言这是惯用的方式。

\n\n
library(data.table)\ndf1 <- data.frame(A=1, B=2)\ndf2 <- data.frame(D=3)\n\nlist2env(eapply(.GlobalEnv, function(x) {if(is.data.frame(x)) {setDT(x)} else {x}}), .GlobalEnv)\n\ndf1[, rn:=.I]\ndf1\n   A B rn\n1: 1 2  1\n
Run Code Online (Sandbox Code Playgroud)\n\n
\n\n

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

\n\n
set.seed(0L)\nsz <- 1e7\ndf1 <- data.frame(A=rnorm(sz))\ndf2 <- data.frame(B=rnorm(sz))\ndf3 <- copy(df1)\ndf4 <- copy(df2)\n\nmicrobenchmark::microbenchmark(unit="ms", times=1L,\n    assign_mtd = {\n        for (x in ls()) {\n            if (is.data.frame(get(x))) {\n                assign(x, as.data.table(get(x)))\n            }\n        }\n    },\n    eval_sub_mtd = {\n        for(x in ls()){\n            if (is.data.frame(get(x))) {\n                eval(substitute(setDT(x), list(x=as.name(x))))\n            }\n        }\n    },\n    eapply_mtd = {\n        list2env(eapply(.GlobalEnv, function(x) {\n                if (is.data.frame(x)) setDT(x) else x\n            }), .GlobalEnv)\n    }\n)\n
Run Code Online (Sandbox Code Playgroud)\n\n

时间安排:

\n\n
Unit: milliseconds\n         expr        min         lq       mean     median         uq        max neval\n   assign_mtd 115.922802 115.922802 115.922802 115.922802 115.922802 115.922802     1\n eval_sub_mtd   3.293358   3.293358   3.293358   3.293358   3.293358   3.293358     1\n   eapply_mtd   1.913802   1.913802   1.913802   1.913802   1.913802   1.913802     1\n
Run Code Online (Sandbox Code Playgroud)\n