如何让data.table将输入识别为变量值而非列名?
解决data.table优先解析列名而非上层变量的问题
嘿,这个坑我踩过好多次!data.table的[]语法在求值时,会优先在数据表的列中查找你写的符号,而不是全局环境(或上层函数环境)里的变量,这就是为啥你期望返回0L,结果却拿到了整个dt的原因。
先补全你的可复现代码,方便大家测试:
library(data.table) dt <- structure( list( zip_from = rep("1000", 10), zip_to = paste0("100", 0:9), time_1 = c(0, 332.8, 332.8, 362.5, 504.9, 256.6, 446.1, 298.3, 312.7, 401.2) ), class = c("data.table", "data.frame"), row.names = c(NA, -10L) ) # 典型错误场景:变量名和列名冲突,data.table直接用列值而非变量 zip_from <- "1001" # 这行会返回10L(全部数据),因为两边都是列zip_from,永远相等 dt[zip_from == zip_from, .N]
下面给出几种实用的解决方案,按推荐程度排序:
使用
..前缀(最简洁)..是data.table的专属语法糖,专门用来告诉它:“去上层环境找这个变量,不要看列”。比如:zip_from <- "1001" # 正确写法:用..zip_from引用上层变量 dt[zip_from == ..zip_from, .N] # 返回1L,符合预期使用
get()函数明确指定环境get()可以直接从指定环境中获取变量,默认是上层环境,也能完美解决问题:zip_from <- "1001" dt[zip_from == get("zip_from"), .N] # 返回1L # 也可以明确指定全局环境,更清晰 dt[zip_from == get("zip_from", envir = .GlobalEnv), .N]用括号强制求值上层变量
不管是在i还是j参数里,用括号包裹变量可以强制优先求值上层环境的变量:zip_from <- "1001" # i参数中使用 dt[zip_from == (zip_from), .N] # j参数中返回变量值 dt[, (zip_from)]重命名变量(最稳妥的预防措施)
如果不想记特殊语法,最简单的办法就是不要让变量名和列名重名,比如把变量改成target_zip_from而非zip_from,这样data.table就不会搞混:target_zip_from <- "1001" dt[zip_from == target_zip_from, .N] # 直接正确返回1L
回到你的问题,只要把你原本的代码里的变量引用换成上面的任意一种写法,就能让data.table正确识别你传入的是上层变量,而非列名,从而得到你期望的0L结果。
内容的提问来源于stack exchange,提问作者phabi
相关产品推荐
相关产品推荐

