Converting all data.frames in environment to data.tables
setDT
operates on the name/symbol, while get
returns the value of the object. You can construct the setDT expression and evaluate it:
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]
I would use a loop rather than lapply
to avoid complications (eg, with the evaluating environment).
This should do the trick:
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]
I guess (not sure though) that the for/lapply
loop uses sort of an own environment which messes up with the by ref semantics of data.table
.
A little late, but this seems like a great—and rare—use eapply()
(along with list2env()
). Of course, this is another option, certainly not asserting it is the idiomatic way.
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
Some timings and memory usage:
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)
}
)
timings:
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