以 tidyverse 方式更改列中的多个值

Change multiple values in column in a tidyverse fashion

为了便于说明,我们使用内置的 mpg 数据。

> mpg %>% select(model) %>% unique()
#   model             
#   <chr>             
# 1 a4                
# 2 a4 quattro        
# 3 a6 quattro  
# ...

我想将“a4 quattro”的所有值更改为“a4”,将“a6 quattro”更改为“a6”。我知道 gsub

> mpg <- mpg %>% mutate(model = gsub("a4 quattro", "a4", model))
> mpg <- mpg %>% mutate(model = gsub("a6 quattro", "a6", model))

但是我有办法在一行中做到这一点吗?

此外,有没有办法进一步概括这一点?假设我有一个嵌套的列表类型对象,其结构为

> a
# $a4
# [1] "a4 quattro" "a4 model 2" "model 3"   
#
# $a6
# [1] "a6 quattro" "model k" 

有没有一种简单的方法可以将 mpg(我们的数据)中存在的 a$a4 中元素的所有实例更改为子列表“a4”的名称,a$a6 也一样(可能更多)列出 a) 中的元素? 或者是否有“更好”的数据结构可用于此?

我希望以“tidyverse”方式完成此操作。 Purrr 功能还可以,但不能用于循环。

提前致谢。

您可以使用 recode 进行精确匹配并将一个值替换为另一个值。

library(tidyverse)
mpg %>% 
   mutate(model = recode(model, 'a4 quattro' = 'a4', 'a6 quattro' = 'a6'))

也许如果你有像这里这样的模式,你可以使用一些正则表达式来获得所需的输出。

mpg %>% 
  mutate(model = sub(' quattro', '', model))

对于有限的值,您可以使用 case_when :

mpg %>%
  mutate(model = case_when(model %in% c("a4 quattro", "a4 model 2", "model 3") ~ 'a4', 
                           model %in% c("a6 quattro", "model k") ~'a6', 
                           TRUE ~ model))

一个更通用的解决方案,如果您已经有一个列表,您可以将其转换为数据框并与原始数据连接。

a <- list(a4 = c("a4 quattro", "a4 model 2", "model 3"), 
          a6 = c("a6 quattro", "model k"))

enframe(a) %>%
  unnest(value) %>%
  inner_join(mpg, by = c('value' = 'model'))