Многократное, гибкое сравнение логических столбцов в Data.table - PullRequest
0 голосов
/ 02 января 2019

Я хочу сравнить несколько столбцов в таблице данных в 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

Ответы [ 2 ]

0 голосов
/ 02 января 2019

Функциональный подход - это круто, но вместо этого я предпочитаю пешехода 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
0 голосов
/ 02 января 2019

Используя здесь функциональный подход через 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
...