R - 如何创建重复

时间:2016-08-26 20:18:37

标签: r if-statement

我非常熟悉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是很好的。

4 个答案:

答案 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