4

I have data in the format outlined below, where all of the variables I need to work with are either NA or the name of the variable, and I need to change the NAs to 0 and the strings to 1. I'm trying to use dplyr::across() and ifelse(), but what gets returned is all 1s. The only solution I have right now that works is mutating each variable individually.

How would I change all NAs to 0 and all strings to 1 across multiple variables at once?

library(dplyr)
color_names <- c("black", "grey", "white", "purple")

my_colors <- tribble(
  ~black, ~grey, ~white,  ~purple,
  NA,     "grey", NA,     "purple",
  NA,     NA,     "white", NA,
  "black",NA,     NA,      NA,
  NA,     "grey",  NA,     NA
)

my_colors %>%
  mutate(across(all_of(color_names), ~ifelse(is.na(cur_column()), 0, 1)))
#> # A tibble: 4 x 4
#>   black  grey white purple
#>   <dbl> <dbl> <dbl>  <dbl>
#> 1     1     1     1      1
#> 2     1     1     1      1
#> 3     1     1     1      1
#> 4     1     1     1      1

Created on 2021-01-13 by the reprex package (v0.3.0)

Emma
  • 63
  • 1
  • 6

4 Answers4

4

Using across you can avoid ifelse by doing :

library(dplyr)
my_colors %>% mutate(across(.fns = ~+(!is.na(.))))

However, you can also avoid across since is.na works with dataframes/tibbles.

my_colors[] <- +(!is.na(my_colors))
my_colors

#A tibble: 4 x 4
#  black  grey white purple
#  <int> <int> <int>  <int>
#1     0     1     0      1
#2     0     0     1      0
#3     1     0     0      0
#4     0     1     0      0

!is.na(.) returns a logical vector TRUE/FALSE and + is used to convert them to 1/0.

Ronak Shah
  • 377,200
  • 20
  • 156
  • 213
2

I guess you could do it like this:

library(tidyverse)
color_names <- c("black", "grey", "white", "purple")

my_colors <- tribble(
  ~black, ~grey, ~white,  ~purple,
  NA,     "grey", NA,     "purple",
  NA,     NA,     "white", NA,
  "black",NA,     NA,      NA,
  NA,     "grey",  NA,     NA
)

my_colors %>% 
  mutate(across(.cols = everything(),
                .fns = ~ ifelse(is.na(.x) == TRUE, 0, 1)))

# A tibble: 4 x 4
  black  grey white purple
  <dbl> <dbl> <dbl>  <dbl>
1     0     1     0      1
2     0     0     1      0
3     1     0     0      0
4     0     1     0      0
jared_mamrot
  • 22,354
  • 4
  • 21
  • 46
0

You can try this:

my_colors %>% mutate(across(everything(), ~if_else(is.na(.x), 0, 1)))

nyk
  • 670
  • 5
  • 11
0

This also works, I think is the simplest way.

tribble(
  ~black, ~grey, ~white,  ~purple,
  NA,     "grey", NA,     "purple",
  NA,     NA,     "white", NA,
  "black",NA,     NA,      NA,
  NA,     "grey",  NA,     NA
) %>% 
  modify(~ ifelse(is.na(.), 0, 1))

# A tibble: 4 x 4
  black  grey white purple
  <dbl> <dbl> <dbl>  <dbl>
1     0     1     0      1
2     0     0     1      0
3     1     0     0      0
4     0     1     0      0
Alvaro Morales
  • 1,845
  • 3
  • 12
  • 21