6

I have a data.frame like this:

  value     condition
1  0.46   value > 0.5
2  0.96 value == 0.79
3  0.45 value <= 0.65
4  0.68 value == 0.88
5  0.57   value < 0.9
6  0.10  value > 0.01
7  0.90  value >= 0.6
8  0.25  value < 0.91
9  0.04   value > 0.2

structure(list(value = c(0.46, 0.96, 0.45, 0.68, 0.57, 0.1, 0.9, 
0.25, 0.04), condition = c("value > 0.5", "value == 0.79", "value <= 0.65", 
"value == 0.88", "value < 0.9", "value > 0.01", "value >= 0.6", 
"value < 0.91", "value > 0.2")), class = "data.frame", row.names = c(NA, 
-9L))

I would like to evaluate the strings in the condition column for every row.

So the result would look like this.

  value     condition  goal
1  0.46   value > 0.5 FALSE
2  0.96 value == 0.79 FALSE
3  0.45 value <= 0.65  TRUE
4  0.68 value == 0.88 FALSE
5  0.57   value < 0.9  TRUE
6  0.10  value > 0.01  TRUE
7  0.90  value >= 0.6  TRUE
8  0.25  value < 0.91  TRUE
9  0.04   value > 0.2 FALSE

I suppose there is a handy NSE solution within the dplyr framework. I have experimented with !! and expr() and others. I got some promising results when trying to subset by condition using

result <- df[0,]
for(i in 1:nrow(df)) { 
  result <- rbind(result, filter_(df[i,], bquote(.(df$condition[i]))))
}

But I don't like the solution and it's not exactly what I'm after.

I hope someone can help.

UPDATE: I'm trying to avoid eval(parse(..)).

3

Not entirely sure whether you are looking for something like this, however, you can also use lazy_eval() from lazyeval:

df %>%
 rowwise() %>%
 mutate(res = lazy_eval(sub("value", value, condition)))

  value condition     res  
  <dbl> <chr>         <lgl>
1 0.46  value > 0.5   FALSE
2 0.96  value == 0.79 FALSE
3 0.45  value <= 0.65 TRUE 
4 0.68  value == 0.88 FALSE
5 0.570 value < 0.9   TRUE 
6 0.1   value > 0.01  TRUE 
7 0.9   value >= 0.6  TRUE 
8 0.25  value < 0.91  TRUE 
9 0.04  value > 0.2   FALSE

And even though it is very close to eval(parse(...)), a possibility is also using parse_expr() from rlang:

df %>%
 rowwise() %>%
 mutate(res = eval(rlang::parse_expr(condition)))
3

One straightforward and easy solution would be using eval(parse...

library(dplyr)

df %>%
  rowwise() %>%
  mutate(goal = eval(parse(text = condition)))

# A tibble: 9 x 3
#  value condition     goal 
#  <dbl> <chr>         <lgl>
#1 0.46  value > 0.5   FALSE
#2 0.96  value == 0.79 FALSE
#3 0.45  value <= 0.65 TRUE 
#4 0.68  value == 0.88 FALSE
#5 0.570 value < 0.9   TRUE 
#6 0.1   value > 0.01  TRUE 
#7 0.9   value >= 0.6  TRUE 
#8 0.25  value < 0.91  TRUE 
#9 0.04  value > 0.2   FALSE

However, I would recommend reading some posts before using it.

  • 1
    That's true of course, I know eval(parse(..)) but I try to find a solution without it using NSE in dplyr. I should have been more specific about it. – Humpelstielzchen Apr 23 at 8:56
3

Using match.fun:

# get function, and the value
myFun <- lapply(strsplit(df1$condition, " "), function(i){
  list(f = match.fun(i[ 2 ]), 
       v = as.numeric(i[ 3 ]))
})

df1$goal <- mapply(function(x, y){ 
  x[[ "f" ]](y, x[ "v" ])
  }, x = myFun, y = df1$value)

#   value     condition  goal
# 1  0.46   value > 0.5 FALSE
# 2  0.96 value == 0.79 FALSE
# 3  0.45 value <= 0.65  TRUE
# 4  0.68 value == 0.88 FALSE
# 5  0.57   value < 0.9  TRUE
# 6  0.10  value > 0.01  TRUE
# 7  0.90  value >= 0.6  TRUE
# 8  0.25  value < 0.91  TRUE
# 9  0.04   value > 0.2 FALSE
2

If you want to avoid eval(parse... you can try this:

library(tidyverse)
df %>% mutate(bound = as.numeric(str_extract(condition, "[0-9 \\.]*$")),
              goal = case_when(grepl("==", condition) ~ value == bound,
                               grepl(">=", condition) ~ value >= bound,
                               grepl("<=", condition) ~ value <= bound,
                               grepl(">", condition) ~ value > bound,
                               grepl("<", condition) ~ value < bound,
                               T ~ NA))

  value     condition bound  goal
1  0.46   value > 0.5  0.50 FALSE
2  0.96 value == 0.79  0.79 FALSE
3  0.45 value <= 0.65  0.65  TRUE
4  0.68 value == 0.88  0.88 FALSE
5  0.57   value < 0.9  0.90  TRUE
6  0.10  value > 0.01  0.01  TRUE
7  0.90  value >= 0.6  0.60  TRUE
8  0.25  value < 0.91  0.91  TRUE
9  0.04   value > 0.2  0.20 FALSE

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.