在R的data.table中编写函数:除get()外的变量引用方法
替代
get()的data.table函数实现方案 嘿,很高兴看到你在折腾data.table的函数封装!你现在用get()来处理字符型变量名的方式完全没问题,但data.table还有几种更贴合它惯用风格的实现方式,我给你梳理一下:
方法1:符号求值(推荐)
利用R的非标准求值特性,把字符型变量名转换成符号,再用!!(bang-bang)在data.table的表达式中引用。这种写法和你直接写DT[, ..., by=V1]的原生风格完全一致,可读性拉满:
library(data.table) library(rlang) # 新版data.table也支持base的as.name(),可替代sym() DT <- data.table( V1=rep(letters[1:3],5), V2=c(2:16) ) Test1 <- DT[,.((V2-sd(V2))/(max(V2)-min(V2))), by=.(V1)] # 原对比用例 Norma_sym <- function(dataset, Vari, group_by){ # 把字符转成符号 vari_sym <- sym(Vari) group_sym <- sym(group_by) # 用!!引用符号,写法和原生data.table代码一致 dataset[, .((!!vari_sym - sd(!!vari_sym))/(max(!!vari_sym)-min(!!vari_sym))), by=.(!!group_sym)] } Test2_sym <- Norma_sym(DT, "V2", "V1") all.equal(Test1, Test2_sym) # 返回TRUE,结果完全一致
如果不想依赖rlang包,用base R的as.name()替代sym()效果完全一样:vari_sym <- as.name(Vari)
方法2:利用.SDcols
.SDcols是data.table中用来指定要操作的列的参数,适合需要批量处理多列的场景,单变量也能轻松驾驭:
Norma_SD <- function(dataset, Vari, group_by){ # .SDcols指定要处理的列,.SD代表选中的列集合 dataset[, .((.SD[[1]] - sd(.SD[[1]]))/(max(.SD[[1]]) - min(.SD[[1]]))), by=.(get(group_by)), .SDcols=Vari] } Test2_SD <- Norma_SD(DT, "V2", "V1") all.equal(Test1, Test2_SD) # 返回TRUE # 如果想把group_by也换成非get的写法,结合方法1的符号求值即可: Norma_SD2 <- function(dataset, Vari, group_by){ group_sym <- sym(group_by) dataset[, .((.SD[[1]] - sd(.SD[[1]]))/(max(.SD[[1]]) - min(.SD[[1]]))), by=.(!!group_sym), .SDcols=Vari] } Test2_SD2 <- Norma_SD2(DT, "V2", "V1") all.equal(Test1, Test2_SD2) # 返回TRUE
这种方法的优势在于,如果你需要同时标准化多个变量,只需要把.SD[[1]]改成lapply(.SD, function(x) (x - sd(x))/(max(x)-min(x))),就能一键批量处理,非常灵活。
关于原get()方法的补充
其实你最初用get()的写法是完全有效的,尤其是对于新手来说容易理解。只是当你需要处理更复杂的表达式或者链式操作时,符号求值的写法会更简洁优雅。
内容的提问来源于stack exchange,提问作者Grec001
相关产品推荐
相关产品推荐

