如何根据该列的值中是否存在字符串来替换列中某些索引处的值使用 dplyr 并重复无循环?​​

问题描述

使用 mtcars 的示例:

data(mtcars)
mtcars$car <- row.names (mtcars)

在汽车一栏:我的车名是“Mazda RX4”、“Mazda RX4 Wag”、“Datsun 710”、“Hornet 4 Drive”等。假设我想删除汽车型号,只离开制造商例如“Mazda”、“Datsun”、“Hornet”,也假设名称的格式不是总是以制造商作为第一个,所以我也可以有一个名字为汽车为“ModelX Mazda”或“model Tesla XX”,所以我不能提取制造商作为字符串的第一个词。

如果您有一个包含所有制造商名称 c("Mazda","Datsun","Hornet") 的字符串,您将如何执行此任务?

解决方法

如果有模式字符串,我们可以通过用 paste 折叠来创建单个字符串

v1 <- c("Mazda","Datsun","Hornet")
pat <- paste0(".*\\b(",paste(v1,collapse="|"),")\\b.*")

然后使用 sub 并将这些模式作为一个组捕获

mtcars$car[2] <- "RX4 Mazda Wag" # // changed for testing
out <- sub(pat,"\\1",mtcars$car)
head(out,5)
#[1] "Mazda"  "Mazda"  "Datsun" "Hornet" "Hornet"

或者使用 dplyr

library(dplyr)
library(stringr)
mtcars <- mtcars %>%
       mutate(car = str_replace(car,pat,'\\1'))
,

您也可以使用 str_extract,如下所示:

vec <- c("Mazda","Hornet")

str_extract(mtcars$car,str_c(v,collapse = '|'))

当然,如果您觉得给定汽车制造商的模型可能包含不同的汽车制造商,那么您应该用边界包裹模式。 即

str_extract(mtcars$car,sprintf("\\b(%s)\\b",collapse = '|')))
,

你可以使用fuzzyjoin包并做一个regex_left_join

to_match <- c("Mazda","Hornet")

library(tidyverse)

df <- 
  mtcars %>% 
    rownames_to_column('car')

library(fuzzyjoin)

df %>% 
  regex_left_join(tibble(to_match),by = c('car' = 'to_match')) %>% 
  select(car,to_match) %>% 
  head
#>                 car to_match
#> 1         Mazda RX4    Mazda
#> 2     Mazda RX4 Wag    Mazda
#> 3        Datsun 710   Datsun
#> 4    Hornet 4 Drive   Hornet
#> 5 Hornet Sportabout   Hornet
#> 6           Valiant     <NA>

reprex package (v2.0.0) 于 2021 年 5 月 16 日创建