gojomoso
gojomoso

Reputation: 163

Replace NA or Specific Value with a Value

Code:

library(dplyr)
library(magrittr)

a = c("aa", "bb", "cc", NA, "aa") 
b = c("aa", "bb", "cc", "bb", "bb") 
c = c(NA, "aa", "aa", NA, "bb") 
d = c(1, 1, 2, 2, 3)
df = data.frame(a,b,c,d)

cols <- c("a","b","c")
    
missing <- function(x) {
  replace(x, ifelse(is.na(x), "Missing", ifelse(x == "aa", "Missing",x)))
}

df %<>%
  mutate(across(where(is.character), missing))

I want to evaluate multiple columns in a df and change NAs or any "aa" value to "Missing". I want to create a succinct function to call but I can't figure out how to make it work as I get the following error:

Error: Problem with mutate() input ..1. x argument "values" is missing, with no default i Input ..1 is across(where(is.character), missing).

Desired Output:

a        b        c        d
missing  missing  missing  1
bb       bb       missing  1
cc       cc       missing  2
missing  bb       missing  2
missing  bb       bb       3

Upvotes: 0

Views: 276

Answers (4)

Alan G&#243;mez
Alan G&#243;mez

Reputation: 378

A Base R solution is as follows:

df[df=="aa" | is.na(df)]="missing"

DATA:

a <-  c("aa", "bb", "cc", NA, "aa") 
b <-  c("aa", "bb", "cc", "bb", "bb") 
c <-  c(NA, "aa", "aa", NA, "bb") 
d <-  c(1, 1, 2, 2, 3)
df <- data.frame(a,b,c,d)
cols <- c("a","b","c")

OUTPUT:

        a       b       c d
1 missing missing missing 1
2      bb      bb missing 1
3      cc      cc missing 2
4 missing      bb missing 2
5 missing      bb      bb 3

Upvotes: 1

Darren Tsai
Darren Tsai

Reputation: 35554

You can use na_if() to replace "aa" to NA and replace_na() to replace NA with "missing".

library(dplyr)
library(tidyr)

cols <- c("a", "b", "c")

df %>%
  mutate(across(cols, ~ replace_na(na_if(.x, "aa"), "missing")))

#         a       b       c d
# 1 missing missing missing 1
# 2      bb      bb missing 1
# 3      cc      cc missing 2
# 4 missing      bb missing 2
# 5 missing      bb      bb 3

You cam also use fct_explicit_na() from forcats.

library(forcats)

df %>%
  mutate(across(cols, ~ fct_explicit_na(na_if(.x, "aa"))))

#           a         b         c d
# 1 (Missing) (Missing) (Missing) 1
# 2        bb        bb (Missing) 1
# 3        cc        cc (Missing) 2
# 4 (Missing)        bb (Missing) 2
# 5 (Missing)        bb        bb 3

Upvotes: 1

Bruno
Bruno

Reputation: 4151

You can use anonymous functions inside across like this

library(tidyverse)

a <-  c("aa", "bb", "cc", NA, "aa") 
b <-  c("aa", "bb", "cc", "bb", "bb") 
c <-  c(NA, "aa", "aa", NA, "bb") 
d <-  c(1, 1, 2, 2, 3)
df <- data.frame(a,b,c,d)

cols <- c("a","b","c")


df %>%
  mutate(across(.cols = where(is.character),
                .fns = ~ case_when(.x %>% is.na ~ "Missing",
                .x == "aa" ~ "Missing",
                TRUE ~ .x)
  )
)

Another option is to use a a regular function

test_function <- function(col) {
  case_when(col %>% is.na() ~ "Missing",
            col == "aa" ~ "Missing",
            TRUE ~ col)
}

df %>% 
  mutate(across(.cols = where(is.character),
                .fns = test_function)
  )

Upvotes: 1

Duck
Duck

Reputation: 39585

Try this solution using across():

library(dplyr)
library(magrittr)
#Data
a = c("aa", "bb", "cc", NA, "aa") 
b = c("aa", "bb", "cc", "bb", "bb") 
c = c(NA, "aa", "aa", NA, "bb") 
d = c(1, 1, 2, 2, 3)
df = data.frame(a,b,c,d,stringsAsFactors = F)
#Vector
cols <- c("a","b","c")
#Code
df %>%
  mutate(across(cols, ~ ifelse(.=='aa' | is.na(.), 'Missing', .)))

Output:

        a       b       c d
1 Missing Missing Missing 1
2      bb      bb Missing 1
3      cc      cc Missing 2
4 Missing      bb Missing 2
5 Missing      bb      bb 3

Upvotes: 1

Related Questions