批量转data.frame为data.table后用:=触发警告的规范解法问询
解决批量转换data.frame到data.table的警告问题
首先得搞明白为啥你用lapply或者循环列表的方式转换后,用:=会弹出那个警告——核心原因是你修改的是副本,不是环境里的原始对象。
当你用mget(ls())把环境里的对象取出来放进列表,或者直接把df3、df4塞进list(df3, df4)时,R会创建这些data.frame的副本。这时候你用setDT(l)修改的是列表里的那个副本,而环境里的原始对象其实是被“间接”转成data.table的,这个过程破坏了data.table内部的引用机制,所以后来用:=的时候就会触发警告——因为它得先复制一份才能完成修改。
而你逐个用setDT(df5)的时候,是直接在环境里修改原始对象,自然就不会有这个问题。
那正确的批量转换写法,核心就是直接在当前环境中操作原始对象,别先把它们放进列表再修改副本。下面给你几种靠谱的写法:
方法1:用eapply遍历环境并修改(推荐)
eapply可以直接遍历指定环境里的所有对象,修改后自动替换回去,省心又规范:
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) # 批量转换当前环境中的所有data.frame为data.table eapply(.GlobalEnv, function(x) { if (is.data.frame(x)) setDT(x) else x }) # 现在操作不会有警告 df1[, rn := .I]
方法2:结合ls、get和assign手动操作
如果想更灵活地筛选对象(比如只转换名字以df开头的),可以用这种方式:
# 获取当前环境中所有data.frame的名字 df_names <- ls()[sapply(mget(ls()), is.data.frame)] # 逐个转换并替换回环境 for (name in df_names) { dt <- get(name) setDT(dt) assign(name, dt, envir = .GlobalEnv) } # 测试操作 df1[, rn := .I] # 无警告
方法3:用setDT直接操作环境中的对象(简洁版)
另一种更简洁的写法,直接在循环里用get配合envir参数:
for (name in ls()[sapply(mget(ls()), is.data.frame)]) { setDT(get(name), envir = .GlobalEnv) }
为啥这些写法不会触发警告?
因为它们都是直接在当前环境中修改原始的data.frame对象,setDT可以原地转换(不需要复制),完整保留了data.table内部的引用完整性,后续用:=的时候就能直接按引用修改,不需要额外复制,自然就不会弹出警告了。
另外还要注意几个避坑点:
- 别用
names<-或者attr<-这类会复制整个data.table的操作,尽量用data.table提供的setnames、setattr来修改属性 - 如果是在函数里批量转换,要注意环境的问题,确保操作的是目标环境里的对象
内容的提问来源于stack exchange,提问作者chinsoon12
相关产品推荐
相关产品推荐

