Heikki
Heikki

Reputation: 2254

Add dynamic subset conditions as variables into the data.frame

I have a data frame like

> x = data.frame(A=c(1,2,3),B=c(2,3,4))
> x
  A B
1 1 2
2 2 3
3 3 4

and subsetting conditions in a data frame like

> cond = data.frame(condition=c('A>1','B>2 & B<4'))
> cond
  condition
1       A>1
2 B>2 & B<4

which I then apply dynamically

> eval(parse(text=paste0("subset(x,",cond[1,'condition'],")")))
  A B
2 2 3
3 3 4
> eval(parse(text=paste0("subset(x,",cond[2,'condition'],")")))
  A B
2 2 3

Now, instead of subsetting, I would like to add the subsetting conditions as variables into the data. The end result would look like

  A B condition1 condition2
1 1 2          0          0  
2 2 3          1          1
3 3 4          1          0

How could I derive the above table using the dynamic conditions?

Upvotes: 1

Views: 78

Answers (2)

akrun
akrun

Reputation: 887291

Here is an option using tidyverse

library(tidyverse)
x %>%   
  mutate(!!! rlang::parse_exprs(str_c(cond$condition, collapse=";"))) %>% 
  rename_at(3:4, ~ paste0("condition", 1:2))
#  A B condition1 condition2
#1 1 2      FALSE      FALSE
#2 2 3       TRUE       TRUE
#3 3 4       TRUE      FALSE

If needed, the logical columns can be easily converted to binary with as.integer

Upvotes: 0

Ronak Shah
Ronak Shah

Reputation: 389055

Before using eval parse, I hope you have gone through some readings like

What specifically are the dangers of eval(parse(…))?

and many others which are available.

However, to answer your question, we can continue your flow and use eval parse in sapply

+(sapply(seq_len(nrow(cond)), function(i) 
            eval(parse(text=paste0("with(x,",cond[i,'condition'],")")))))

#     [,1] [,2]
#[1,]    0    0
#[2,]    1    1
#[3,]    1    0

To add it to the dataframe,

x[paste0("condition", 1:nrow(cond))] <- 
         +(sapply(seq_len(nrow(cond)), function(i) 
         eval(parse(text=paste0("with(x,",cond[i,'condition'],")")))))

x
#  A B condition1 condition2
#1 1 2          0          0
#2 2 3          1          1
#3 3 4          1          0

Simplifying it a bit (using @jogo's comment)

+(sapply(cond$condition, function(i) with(x, eval(parse(text=as.character(i))))))

#     [,1] [,2]
#[1,]    0    0
#[2,]    1    1
#[3,]    1    0

Upvotes: 2

Related Questions