Evaluate different logical conditions from string for each row

后端 未结 4 1694
小鲜肉
小鲜肉 2020-12-11 18:33

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.         


        
相关标签:
4条回答
  • 2020-12-11 19:08

    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
    
    0 讨论(0)
  • 2020-12-11 19:12

    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.

    0 讨论(0)
  • 2020-12-11 19:14

    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)))
    
    0 讨论(0)
  • 2020-12-11 19:19

    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
    
    0 讨论(0)
提交回复
热议问题