Using case_when() within mutate_at() to recode several columns with different types of NA
Solution 1:
library(dplyr)
df %>%
mutate_at(vars(-c(cold)), ~ case_when(colc >= 0.5 ~ `is.na<-`(., TRUE), TRUE ~ .))
# cola colb colc cold
# 1 q 156 0.2071403 a
# 2 <NA> NA NA b
# 3 r 6 0.4020175 a
# 4 b 100 0.3829481 b
# 5 t 49 0.4885119 a
# 6 z 31 0.2631685 b
# 7 d 189 0.3859104 a
# 8 <NA> NA NA b
# 9 <NA> NA NA a
# 10 g 171 0.4743554 b
Description
When you use case_when
to assign NA
, you need to specify the type of NA
, i.e. NA_integer_
, NA_real_
, NA_complex_
and NA_character_
. However, mutate_at
transforms multiple columns at the same time and these columns have different types, so you cannot apply one statement on all columns. Ideally, there might exist something like NA_guess
to identify the type, but I don't find that so far. This method is a little tricky. I use is.na()
to convert the input vector to NAs, and these NAs will be the same type as the input vector. For example:
x <- 1:5
is.na(x) <- TRUE ; x
# [1] NA NA NA NA NA
class(x)
# [1] "integer"
y <- letters[1:5]
is.na(y) <- TRUE ; y
# [1] NA NA NA NA NA
class(y)
# [1] "character"
Solution 2:
Work around similar to @NelsonGon :
library(dplyr)
df %>%
mutate_all(as.character) %>%
mutate_at(vars(-c(cold)),
~case_when(colc >= 0.5 ~ NA_character_, # ifelse(is.numeric(.), NA_real_, NA_character_),
TRUE ~ .
)
) %>%
mutate(colb = as.numeric(colb),
colc = as.numeric(colc)
)
#> cola colb colc cold
#> 1 q 156 0.2071403 a
#> 2 <NA> <NA> NA b
#> 3 r 6 0.4020175 a
#> 4 b 100 0.3829481 b
#> 5 t 49 0.4885119 a
#> 6 z 31 0.2631685 b
#> 7 d 189 0.3859104 a
#> 8 <NA> <NA> NA b
#> 9 <NA> <NA> NA a
#> 10 g 171 0.4743554 b