如何在data.table中根据列名跨引用对应行的列值?
解决data.table中根据列名列逐行提取对应值的问题
我明白你的问题了——你想让每行根据v1列里存储的列名,提取对应列的对应行值,但用get()的时候得到了整列的重复值,而不是逐行匹配的结果。这是因为get()在data.table的j表达式里是按列向量处理的:它只会取v1的第一个元素(也就是'vs')对应的列,然后把整列的值赋值给v2,所以才得到了[0,0,1](也就是vs列的前三个值),而不是你期望的[0,1,4]。
下面给你几种可行的解决方案:
方法1:逐行分组(最直观的data.table风格)
利用data.table的分组功能,按每行索引(.I)分组,这样每个分组里v1是单个字符串,然后直接用.SD[[v1]]提取当前行对应列的值:
library(data.table) dt = data.table(mtcars) sub = dt[1:3] sub[, v1 := c('vs', 'am', 'gear')] # 核心代码 sub[, v2 := .SD[[v1]], by = .I]
运行后sub的v2列就是[0,1,4],完全符合你的期望。
方法2:使用mapply逐行匹配
mapply可以遍历v1的每个元素,结合行号提取对应位置的值:
sub[, v2 := mapply(function(col, idx) .SD[[col]][idx], v1, .I)]
这个方法的逻辑是:对每个行号idx和对应的列名col,提取.SD中col列的第idx个元素,最终组合成v2列。
方法3:矩阵索引技巧
先把v1指定的列转换成矩阵,然后提取对角线元素(每行对应列名的位置):
sub[, v2 := as.matrix(sub[, ..v1])[cbind(1:.N, 1:.N)]]
这里..v1表示取v1中存储的列名对应的列,转换成矩阵后,cbind(1:.N,1:.N)会定位到每行的目标列位置,提取出对应的值。
验证结果
无论使用哪种方法,最终sub的结构都会是:
mpg cyl disp hp drat wt qsec vs am gear carb v1 v2 1: 21.0 6 160 110 3.90 2.620 16.46 0 1 4 4 vs 0 2: 21.0 6 160 110 3.90 2.875 17.02 0 1 4 4 am 1 3: 22.8 4 108 93 3.85 2.320 18.61 1 1 4 1 gear 4
内容的提问来源于stack exchange,提问作者Marvin Taschenberger
相关产品推荐
相关产品推荐

