How to simplify handling with nested ifelse() structures in base R?

前端 未结 4 1114
一生所求
一生所求 2021-01-21 08:49

I\'m facing nested ifelse() structures:

df1$var <- ifelse(x < a, u, ifelse(x < b, v, ifelse(x < c, w, ...)))

whereby t

相关标签:
4条回答
  • 2021-01-21 08:54

    You could use case_when from the dplyr library:

    df1$y <- case_when(
        x == 1 ~ "s",
        x == 2 ~ "t",
        x == 3 ~ "u",
        x == 4 ~ "v",
        TRUE ~ "w"
    )
    

    Note that the final case above (TRUE) is the blanket else condition which will catch all cases not matching any earlier conditions.

    0 讨论(0)
  • 2021-01-21 09:00

    I would create an empty vector then fill each condition one by one.

    df1$y = rep(NA,nrow(df1))
    df1$y[x < a] = u(x[x < a])
    df1$y[x > a & x < b] = v(x[x > a & x < b])
    df1$y[x > b & x < c] = w(x[x > b & x < c])
    ...
    

    I have found this to be the clearest way of setting the values, I find it much easier to see at a glance what is happening when you have more conditions than nested ifelse statements.

    df1$y = ifelse(x < a, u(x), ifelse(x < b, v(x), ifelse(x < c, w(x), ...)) )
    

    An improvement on this would be to predefine the condition elements, that way each group is only calculated once:

    aEls = which(x < a)
    bEls = which(x > a & x < b)
    cEls = which(x > b & x < c)
    ...
    
    y = rep(NA,nrow(df1))
    y[aEls] = u(x[aEls])
    y[bEls] = v(x[bEls])
    y[cEls] = w(x[cEls])
    ...
    
    df$y = y
    
    0 讨论(0)
  • 2021-01-21 09:16

    In base R, if there are multiple elements to be replaced, create a key/value dataset and do a merge

    keyval <- data.frame(x = c(1, 2, 3, 4), y = c("s", "t", "u", "v"), stringsAsFactors = FALSE)
    new <- merge(df1, keyval, by = 'x', all.x = TRUE)[['y']]
    new[is.na(new)] <- "w"
    df1$x <- new
    

    data

    set.seed(24)
    df1 <- data.frame(x = rbinom(100, 5, .5))
    
    0 讨论(0)
  • 2021-01-21 09:18

    Since you insist on base R, here are two possibilities:

    Define a mapping data.frame:

    # Define mapping
    map <- cbind.data.frame(
        x = c(1, 2, 3, 4, NA),
        y = c("s", "t", "u", "v", "w"));
    

    Method 1: match entries from map to df1.

    # match entries
    df1$y <- map[match(df1$x, map$x), 2];
    df1$y[is.na(df1$y2)] <- "w";
    

    Method 2: Loop through all mappings, and replace using direct indexing:

    # for loop
    df1$y <- factor("w", levels = map$y);
    for (i in 1:nrow(map)) df1$y[df1$x == map$x[i]] <- map$y[i];
    

    Output:

    tail(df1);
    #    x y
    #95  4 v
    #96  1 s
    #97  4 v
    #98  2 t
    #99  4 v
    #100 1 s
    

    Note, the second method will also work for inequalities.


    Sample data

    set.seed(2017);
    df1 <- data.frame(x = rbinom(100, 5, .5))
    
    0 讨论(0)
提交回复
热议问题