AnEostig
AnEostig

Reputation: 115

Else part of an if_else condition dplyr

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

Upvotes: 1

Views: 453

Answers (2)

r2evans
r2evans

Reputation: 160417

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  

Upvotes: 3

zephryl
zephryl

Reputation: 17069

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

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

Upvotes: 3

Related Questions