r - R 为每行的字符串计算不同的逻辑条件

我有一个类似这样的data.frame:


 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))




我想对每一行的condition 列中的字符串求值。

结果是这样的。


 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



我想 dplyr 框架里有一个方便的NSE解决方案。 我试过!!和expr()。 在使用 condition 进行子集划分时,我得到了一些很有希望的结果


result <- df[0,]


for(i in 1:nrow(df)) { 


 result <- rbind(result, filter_(df[i,], bquote(.(df$condition[i]))))


}




但是我不喜欢这个解决方案,而且它并不完全是我所需要的。

我希望有人能帮助。

更新: 我正在尝试避免 eval(parse(..))

时间:

不过,不完全确定你是否正在寻找这样的内容,你还可以使用 lazyeval 中的lazy_eval():


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



尽管它非常接近 eval(parse(...)),但也有可能使用 rlang 中的parse_expr():


df %>%


 rowwise() %>%


 mutate(res = eval(rlang::parse_expr(condition)))



一个简单而简单的解决方案是使用 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



但是我建议在使用它之前阅读一些帖子

使用 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



如果你想避免 eval(parse...,你可以尝试:


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



...