Data.table 中的多个灵活的逻辑列比较
Posted
技术标签:
【中文标题】Data.table 中的多个灵活的逻辑列比较【英文标题】:Multiple, flexible logical column comparison in Data.table 【发布时间】:2019-05-28 17:27:29 【问题描述】:我想在 R 中比较数据表中的多个列,并且我不想对它们进行硬编码。例如,请参见下面的简单示例:
###########
#Setup data
###########
set.seed(2)
fill = data.table(n=1:7)
Tp=3
for(t in 1:Tp)
set(x = fill, j = paste0('v',t), value = sample(0:10,7))
fill[1,paste0('v',3):=0]
fill[5,paste0('v',2):=0]
fill[5,paste0('v',3):=0]
for(t in 1:Tp)
fill[,paste0('v',t,'prm'):=get(paste0('v',t))]
fill[1,paste0('v',1,'prm'):=0]
fill[2,paste0('v',2,'prm'):=1]
fill[5,paste0('v',3,'prm'):=1]
fill[7,paste0('v',3,'prm'):=2]
所以数据是:
> fill
n v1 v2 v3 v1prm v2prm v3prm
1: 1 2 9 0 0 9 0
2: 2 7 4 8 7 1 8
3: 3 5 10 9 5 10 9
4: 4 1 8 1 1 8 1
5: 5 6 0 0 6 0 1
6: 6 8 7 0 8 7 0
7: 7 0 0 6 0 0 2
我想将每一列与其'prm'进行数字比较,如下所示:
fill[v1==v1prm & v2==v2prm & v3==v3prm]
所以输出是:
> fill[v1==v1prm & v2==v2prm & v3==v3prm]
n v1 v2 v3 v1prm v2prm v3prm
1: 3 5 10 9 5 10 9
2: 4 1 8 1 1 8 1
3: 6 8 7 0 8 7 0
但我不想对此进行硬编码,因为我可能会使用超过 3 列。另外,我可能想使用其他比较,例如...
> fill[v1>v1prm & v2==v2prm & v3==v3prm]
n v1 v2 v3 v1prm v2prm v3prm
1: 1 2 9 0 0 9 0
【问题讨论】:
【参考方案1】:通过Map
在这里使用函数式方法:
## set some variable names
pre <- paste0("v", 1:3)
pst <- paste0(pre, "prm")
## select where they match using `==` and Reduce to combine with a `&` (logical AND)
fill[Reduce(`&`, Map(`==`, mget(pre), mget(pst)))]
# n v1 v2 v3 v1prm v2prm v3prm
#1: 3 5 10 9 5 10 9
#2: 4 1 8 1 1 8 1
#3: 6 8 7 0 8 7 0
扩展此逻辑以循环不同的逻辑比较:
funs <- c(`>`, `==`, `==`)
fill[Reduce(`&`, Map(function(pr,ps,f) f(pr,ps), mget(pre), mget(pst), funs))]
# n v1 v2 v3 v1prm v2prm v3prm
#1: 1 2 9 0 0 9 0
【讨论】:
【参考方案2】:功能性方法的答案很酷,但我更喜欢行人eval/parse
,因为它更容易阅读/维护:
lhs = paste0('v', 1:3)
fns = c('>', '==', '==')
rhs = paste0(pre, 'prm')
fill[eval(parse(text = paste(lhs, fns, rhs, collapse = '&')))]
# n v1 v2 v3 v1prm v2prm v3prm
#1: 1 2 9 0 0 9 0
【讨论】:
以上是关于Data.table 中的多个灵活的逻辑列比较的主要内容,如果未能解决你的问题,请参考以下文章
R语言data.table导入数据实战:data.table生成新的数据列(基于已有数据列)生成多个数据列