R data.table自定义函数内调用列变量的正确语法及报错修复
data.table自定义分组计算相对偏差函数修复方案
测试数据集
library(data.table) set.seed(1) year = c(rep(2000,5), rep(2001,5), rep(2002,5), rep(2003,5), rep(2004,5)) DT <- data.table(panelID = sample(10,10), some_type = as.factor(sample(0:5, 6)), some_other_type = as.factor(sample(0:5, 6)), Group = c(rep(1,20),rep(2,20),rep(3,20),rep(4,20),rep(5,20)), wt = 15*round(runif(100)/10,2), Income = round(rnorm(10,-5,5),2), Income_proxy = round(rnorm(10,-6,6),2), year = rep(year,4), Happiness = sample(10,10), Sex = round(rnorm(10,0.75,0.3),2), Age = sample(100,100), Height= 150*round(rnorm(10,0.75,0.3),2))
原代码核心错误点
- 列引用逻辑错误:传入的
varA、varB是字符串值,直接在[.data.table计算表达式中使用时,R不会将其识别为DT的列,触发object 'Income' not found错误;若手动给列名加引号,字符串无法参与算术运算,触发non-numeric argument to binary operator错误 - 作用域语法错误:
out_names定义在for循环外部,定义时就调用了循环变量i,此时i未赋值,直接触发变量不存在错误 - 分支结构错误:
else if (!is.null(years))后的代码块没有用花括号包裹,后续双层for循环实际不在条件分支内,逻辑完全混乱 - 分组传参错误:多分组场景下
by=eval(groups[i], years[i])写法不符合data.table语法,无法正确识别多列分组规则 - 列名生成逻辑错误:按年份分组的场景下没有按「分组变量+年份」的组合生成独立列名,循环赋值时会反复覆盖同一列结果
- 示例调用语法错误:第二个调用示例末尾多了一个冗余右括号,属于基础语法错误
修正后的函数代码
calculate_relative_dev <- function(DT, varA="Income", varB="Income_proxy", groups, years=NULL) { setDT(DT) # 入参兼容:支持传入裸列名,自动转字符串 if(!is.null(years) & !is.character(years)) years <- deparse(substitute(years)) if(!is.character(groups)) groups <- deparse(substitute(groups)) # 无年份分组场景 if (is.null(years)) { for (i in seq_along(groups)) { out_col <- paste0("rel_deviation_", groups[i]) # 用get()按字符串取对应列计算,by直接支持字符向量分组 DT[, (out_col) := 100 * mean((get(varA) - get(varB)) / get(varA)), by = groups[i]] } } else { # 带年份分组场景:按 分组列+年份 双维度分组计算 for (i in seq_along(groups)) { for (j in seq_along(years)) { out_col <- paste0("rel_deviation_", groups[i], "_", years[j]) DT[, (out_col) := 100 * mean((get(varA) - get(varB)) / get(varA)), by = c(groups[i], years[j])] } } } return(DT) }
注:原函数名calulate_relative_dev存在拼写错误(少写一个l),修正后为标准拼写,如需保留原命名可自行修改函数名
正确调用示例
- 仅按指定列分组计算:
res1 <- calculate_relative_dev(DT, groups = c("Group","some_type"))
- 同时按指定列+年份分组计算(支持裸列名/字符串列名两种传参方式):
# 裸列名传参 res2 <- calculate_relative_dev(DT, groups = c("Group","some_type"), years = year) # 字符串传参 res3 <- calculate_relative_dev(DT, groups = c("Group","some_type"), years = "year")
内容的提问来源于stack exchange,提问作者Tom
相关产品推荐
相关产品推荐

