dplyr alternative for plyr::mapvalues (recode using dictionary)

Viewed 784

plyr::mapvalues makes it possible to recode a vector based on a dictionary, i.e., two matched vector of existing and replacement values.

library(plyr)
data <- c("a", "b", "c", "a")
dict_old <- c("a", "b", "c")
dict_new <- c("Apple", "Banana", "Carrot")
mapvalues(data, dict_old, dict_new)
[1] "Apple"  "Banana" "Carrot" "Apple" 

In dplyr, an equivalent result can be obtained by creating a list containing the new values and assigning the old values as names to the list elements:

list <- as.list(dict_new)
names(list) <- dict_old
recode(data, !!!list)
[1] "Apple"  "Banana" "Carrot" "Apple" 

However, that strikes me as rather kludgy. Is there a cleaner way to do this within the tidyverse?

3 Answers

One way using stringr could be:

str_replace_all(data, setNames(dict_new, dict_old))

[1] "Apple"  "Banana" "Carrot" "Apple" 

We can do this in base R

unname(setNames(dict_new, dict_old)[data])
#[1] "Apple"  "Banana" "Carrot" "Apple" 

If you think using !!! is 'kludgy', you could always hide it away in a neat function. This is how I regularly write bespoke mappings:

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

my_map <- function (x) {
  dict_old <- c("a", "b", "c")
  dict_new <- c("Apple", "Banana", "Carrot")
  dict <- setNames(dict_new, dict_old)
  dplyr::recode(data, !!!dict)
}

my_map(data)
[1] "Apple"  "Banana" "Carrot" "Apple" 
Related