我非常熟悉R的标准ifelse语句,以及如何创建嵌套的ifelse语句。但是我想创建一个“更好”的版本,所以我不必复制/粘贴ifelse这么多次。
以嵌套的ifelse语句为例:
df <- data.frame(b = 1:5)
df$a <- ifelse(df$b == 1,1,
ifelse(df$b == 2,2,
ifelse(df$b == 3,3,4)))
相反,我想做的是创建一个像我这样可以调用的函数:
df$a <- myFunction(df$b == 1,1,
df$b == 2,2,
df$b == 3,3,4)
我希望函数能够获取我输入的参数数量,从而知道要包含多少ifelse语句,然后将参数插入正确的位置,直到我想要的多少。
仍然有一些重复,但是当创建更长的嵌套ifelse语句时,不必重复那段代码,然后尝试跟踪结束的paren是很好的。
答案 0 :(得分:4)
我们可以使用Reduce()
来构建嵌套ifelse()
调用所需的解析树,然后使用eval()
:
ifelses <- function(...) {
## validate number of args is at least 3 and odd
stopifnot(nargs()>=3L);
stopifnot(nargs()%%2L==1L);
## precompute the required number of calls and the argument parse tree list
num <- (nargs()-1L)%/%2L;
cl <- match.call();
## build up the parse tree of nested ifelse() calls using Reduce(), then eval() it
## terminology (following docs): ifelse(test,yes,no)
eval(Reduce(
function(i,noArg) call('ifelse',cl[[i]],cl[[i+1L]],noArg),
seq(2L,by=2L,len=num), ## indexes of "test" args
cl[[length(cl)]], ## first (innermost) "no" arg
T ## proceed from right-to-left, IOW inside-out wrt parse tree
));
}; ## end ifelses()
有用的文档:
演示:
ifelses(c(F,T,F,F),1:4,c(T,F,F,F),5:8,c(F,T,F,T),9:12,13:16);
## [1] 5 2 15 12
OP的例子:
df <- data.frame(b=1:5);
df$a <- ifelses(df$b==1L,1L,df$b==2L,2L,df$b==3L,3L,4L);
df;
## b a
## 1 1 1
## 2 2 2
## 3 3 3
## 4 4 4
## 5 5 4
答案 1 :(得分:1)
抱歉无耻广告 - 您可以在我的包expss
中尝试if_val
功能
b = sample(1:7, 10, replace = TRUE)
if_val(b, 1 ~ 1, 2 ~ 2, 3 ~ 3, other ~ 4)
还有ifs
函数:ifs(b==1 ~ 1, b==2 ~ 2, b==3 ~ 3, TRUE ~ 4)
。
答案 2 :(得分:1)
这是与查找表合并的工作。你可以将它包装在一个函数中,但通常我不会打扰:
df <- data.frame(b = 1:5)
lookupif <- function(df, x, y, else.val = NA, on.col, res.col = "val") {
lookup <- data.frame(x, y)
names(lookup)[1] <- res.col
df <- merge(df, lookup, by.x = on.col, by.y = "y", all.x = TRUE)
df[is.na(df[[res.col]]), res.col] <- else.val
df
}
lookupif(df, 1:3, 1:3, 4, "b")
# b val
#1 1 1
#2 2 2
#3 3 3
#4 4 4
#5 5 4
答案 3 :(得分:1)
dplyr::case_when
是嵌套ifelse
的级联替代品,例如。
library(dplyr)
df <- data.frame(b = 1:5)
df %>% mutate(a = case_when(b == 1 ~ 1,
b == 2 ~ 2,
b == 3 ~ 3,
TRUE ~ 4))
#> b a
#> 1 1 1
#> 2 2 2
#> 3 3 3
#> 4 4 4
#> 5 5 4
或者只是窃取它并将其置于基本语法中:
df$a <- with(df, dplyr::case_when(b == 1 ~ 1,
b == 2 ~ 2,
b == 3 ~ 3,
TRUE ~ 4))
返回同样的东西。
既然它已经变得如此简单而不牺牲ifelse
的多功能性,它可能不需要被放入一个函数中,但如果你愿意,它可以。使用the development version的新rlang NSE语法
add_cases <- function(.data, .col, ...){
.data %>% mutate(!!.col := case_when(!!!quos(...)))
}
df %>% add_cases(.col = 'a',
b == 1 ~ 1,
b == 2 ~ 2,
b == 3 ~ 3,
TRUE ~ 4)
#> b a
#> 1 1 1
#> 2 2 2
#> 3 3 3
#> 4 4 4
#> 5 5 4