How can I apply a simple function to multiple columns?

Viewed 168

I have the following data frame:

df <- data.frame("A" = c("y", "y", "n", "n"),
             "B" = c("n", NA, "y", "y"),
             "C" = c("n", "y", "y", "n"))

I would like to apply the following code to columns A and B:

df$A <- 
  df$A %>% 
  recode(
    "n" = "No",
    "y" = "Yes"
  ) %>% 
  factor(
    levels = c("No", "Yes")
  )

I tried to solve this using the following code using a for loop:

cols <- c("A", "B")

for (i in cols) {
  df$i <- 
    df$i %>% 
    recode(
      "n" = "No",
      "y" = "Yes"
    ) %>% 
    factor(
      levels = c("No", "Yes")
    )
}

However, I get this erroe message:

Error in UseMethod("recode") : 
  no applicable method for 'recode' applied to an object of class "NULL"

Can anybody help me what I am missing here? Thanks for your help!

5 Answers

Using dplyr::across you could do:

library(dplyr)

df <- data.frame("A" = c("y", "y", "n", "n"),
                 "B" = c("n", NA, "y", "y"),
                 "C" = c("n", "y", "y", "n"))

mutate(df, across(c(A, B), ~ recode(.x, "n" = "No","y" = "Yes") %>% factor(levels = c("No", "Yes"))))
#>     A    B C
#> 1 Yes   No n
#> 2 Yes <NA> y
#> 3  No  Yes y
#> 4  No  Yes n

You can use the function factor by specifying both its levels and labels arguments:

library(dplyr)

df <- mutate(df, across(c(A, B), factor, levels=c("n", "y"), labels=c("No", "Yes")))

#     A    B C
# 1 Yes   No n
# 2 Yes <NA> y
# 3  No  Yes y
# 4  No  Yes n

If you want to final output to be factors you can use fct_recode from `forcats.

library(dplyr)
library(forcats)

cols <- c("A", "B")
df <- df %>% mutate(across(all_of(cols), fct_recode, "No" = "n", "Yes" = "y"))
df

#    A    B C
#1 Yes   No n
#2 Yes <NA> y
#3  No  Yes y
#4  No  Yes n

str(df)

#'data.frame':  4 obs. of  3 variables:
# $ A: Factor w/ 2 levels "No","Yes": 2 2 1 1
# $ B: Factor w/ 2 levels "No","Yes": 1 NA 2 2
# $ C: chr  "n" "y" "y" "n"

Base R solution:

# Function performing a mapping replacement:
# replaceMultipleValues => function() 
replaceMultipleValues <- function(df, mapFrom, mapTo){
  valueMap <- setNames(mapTo, mapFrom)
  res <- data.frame(
    matrix(
      valueMap[unlist(df)], 
      nrow = nrow(df),
      ncol = ncol(df),
      dimnames = dimnames(df)
    )
  )
  return(res)
}

# Application of the function: 
# data.frame => stdout(console)
replaceMultipleValues(
  df, 
  c("y", "n"), 
  c("yes", "no")
)

We can use str_replace_all

library(stringr)
library(dplyr)
df %>%
    mutate(across(A:B, ~ str_replace_all(., setNames( c('No', 'Yes'), c('n', 'y')))))
    A    B C
1 Yes   No n
2 Yes <NA> y
3  No  Yes y
4  No  Yes n
Related