Home > front end >  Else part of an if_else condition dplyr
Else part of an if_else condition dplyr

Time:03-15

This is a follow up question to this post

I want to replace values in t1, t2, and t3 according to whether or not column v3 contains a 1, a 2, or a 3 by group in v2.

My goal is to write Nav in column t1 if for a given group of v2 column v3 has value 1.

The problem I face comes from the else part of the statement. I would like that if in the example above v3 does not contain 1 that column t1 stays the same.

Any idea?

mutate(across(starts_with("t"), ~if_else(any(v3==i),"NAv", HERE COLUMN REMAINS UNCHANGED)))
df <- data.frame (v1 = c("Fran", "Fran", "Fran", "Belg", "Belg", "Belg"),
                  v2 = c(1201, 1201, 1202, 1203, 1204, 1205),
                  v3 = c(1, 2, 1, 1, 3, 1),
                  t1 = c(NA,NA,NA,NA,NA,NA),
                  t2 = c(NA,NA,NA,NA,NA,NA),
                  t3 = c(NA,NA,NA,NA,NA,NA)
)


for (i in 1:3) {
  df <- df %>%
    group_by(v2) %>% 
    mutate(across(starts_with("t"), ~if_else(any(v3==i),"NAv", NULL)))
}

CodePudding user response:

Three problems:

  1. Your t* columns in this sample data are of class logical, not character, so I'll coerce them in the first mutate. (This step may not be necessary with your real data.)

  2. You cannot use NULL in any portion of an ifelse/if_else. Since you want to retain the previous value if the condition is not met, then we'll use the . placeholder that across uses.

  3. Using any(.) inside the if_else collapses the length of the first argument condition= will always be seen as length-1; instead, we need to repeat the return from any(.) for as many rows as we have, using rep(.., n()).

df %>%
  mutate(across(starts_with("t"), as.character)) %>%
  group_by(v2) %>%
  mutate(across(starts_with("t"), ~ if_else(rep(any(v3 == 1), n()), "NAv", .) )) %>%
  ungroup()
# # A tibble: 6 x 6
#   v1       v2    v3 t1    t2    t3   
#   <chr> <dbl> <dbl> <chr> <chr> <chr>
# 1 Fran   1201     1 NAv   NAv   NAv  
# 2 Fran   1201     2 NAv   NAv   NAv  
# 3 Fran   1202     1 NAv   NAv   NAv  
# 4 Belg   1203     1 NAv   NAv   NAv  
# 5 Belg   1204     3 NA    NA    NA   
# 6 Belg   1205     1 NAv   NAv   NAv  

CodePudding user response:

in across(), .x stands in for the current column. So:

mutate(across(starts_with("t"), ~ifelse(any(v3==i),"NAv", .x)))
  • Related