R data.table变量提前求值与环境解析异常问题求解
问题原因解答
场景1:循环批量新增列报错问题
你对R求值顺序的误解核心是不熟悉data.table的非标准求值(NSE)规则:
data.table在[]的j位置(即第二个参数位置)默认会优先把符号当成当前数据集的列名解析,而非先去父环境找同名变量。你写的x := ...里的x会被直接当成列名去查找,而非你循环中传入的、值为"V1"的变量x,自然会报V1列不存在的错误。
修复方法很简单:把赋值左侧的变量用括号包裹,告诉data.table先对括号内的表达式求值,再把求值结果作为列名:
lapply(c("V1", "V2", "V3"), function(x){ db[, (x) := get(paste(x, "ACC", sep = "_")) + get(paste(x, "SIC", sep = "_"))] })
如果要更稳妥避免get找错环境,可以明确指定get的求值环境为当前data.table:
get(paste(x, "ACC", sep = "_"), envir = .SD)
场景2:列表内data.table操作父环境变量报错问题
这个问题同样是data.table的NSE优先级导致的:j位置的表达式会优先在当前data.table的列环境中查找符号,所以会先在db[[x]]的列里找tbls对象,找不到才会往上一级环境查找,一旦出现列名和外部变量重名、或者求值顺序异常就会报错。
修复有两种常用方案:
- 提前把父环境的变量提取到局部变量,避免data.table解析歧义:
parent_tbl <- tbls[[x]] db[[x]][, LAPSE_DUR := pmin(max(parent_tbl$LAPSE_DUR), DURATION_Y)]
- 用
get明确指定求值环境为父环境:
db[[x]][, LAPSE_DUR := pmin(max(get("tbls", envir = parent.frame())[[x]]$LAPSE_DUR), DURATION_Y)]
内容的提问来源于stack exchange,提问作者Daniel V
相关产品推荐
相关产品推荐

