Using `mutate_at` and `na_if` together to replace zeros with NA for only some columns

Update

From dplyr 1.0.0 we can use across :

library(dplyr)
df %>% mutate(across(c(vs,am), na_if, 0)) %>% head

#   mpg cyl vs am vs_doubled
#1 21.0   6 NA  1          0
#2 21.0   6 NA  1          0
#3 22.8   4  1  1          2
#4 21.4   6  1 NA          2
#5 18.7   8 NA NA          0
#6 18.1   6  1 NA          2

Original answer

In the previous versions of dplyr we can use mutate_at :

df %>%  mutate_at(vars(vs,am), ~na_if(.,0)) %>% head

Or another way would be

df %>% mutate_at(vars(vs,am), na_if, 0)

~ is purrr-styled formula syntax whereas . represents value of the column. It's an alternative to anonymous function calls with which you would have written the above function as

df %>%  mutate_at(vars(vs,am), function(x) na_if(x, 0)) 

Also the alternative way shown does not require ~ and we can directly pass the function with additional arguments (which is 0 here for y).


And of course there are other ways to do this without using na_if

df %>% mutate_at(vars(vs, am), ~replace(., . == 0, NA)) 

Or the same with base R

cols <- c("vs", "am")
df[cols] <- lapply(df[cols], function(x) replace(x, x == 0, NA))