R data.table中get(x)遇同名列失效,是否为包的Bug?
为什么
get(x)在data.table中与列名冲突时出错?这是Bug吗? 这不是data.table的Bug哦,其实是它的作用域解析规则导致的预期之外的行为,咱们来一步步拆解:
问题根源
在data.table的j表达式(也就是方括号里的第二个参数)中,它会优先在data.table自身的列中查找变量,而不是默认去全局环境找。当你运行dt[, 3*get(x)]时:
- 首先解析
x,因为data.table里有一列叫x(值是1:3),所以这里的x被直接替换成了这个数值向量 - 然后
get()收到的参数是1:3,而get()需要的是字符型的变量名,自然就抛出了invalid first argument的错误
而dt[, 3*get(var)]能正常工作,是因为data.table里没有叫var的列,所以它会去全局环境找var='y',符合get()的参数要求。
解决方法
这里有几种靠谱的方式来绕过这个作用域冲突:
明确指定
get()的查找环境
直接告诉get()去全局环境找变量x:dt[, 3*get(x, envir = .GlobalEnv)] # 输出 [1] 6 9 12使用
..前缀指向父环境
data.table里的..前缀表示“去父环境(比如全局环境)找变量”,用它来修饰x,就能让get()拿到全局的x='y':dt[, 3*get(..x)] # 输出 [1] 6 9 12 # 甚至更简洁,因为..x直接对应全局x指向的列,所以可以直接写: dt[, 3*..x] # 同样得到 [1] 6 9 12用
eval()配合环境指定
如果你需要更灵活的表达式,可以用eval()明确指定环境:dt[, 3*eval(get(x), envir = .GlobalEnv)] # 有效
总结
这是data.table的设计特性——优先解析列名是为了让用户更方便地直接操作列(比如dt[, x+y]不用写dt$x + dt$y)。只要了解这个作用域规则,通过指定环境或者..前缀,就能轻松避免这类变量名冲突的问题啦。
内容的提问来源于stack exchange,提问作者user9210742
相关产品推荐
相关产品推荐

