整洁宇宙(Tidyverse):基于部分匹配替换整个字符串

3
我想使用`stringr`包中的函数基于部分匹配来替换数据中的整个字符串。目前我尝试过使用`str_replace_all()`来替换完全匹配的字符串,但是当需要纠正许多变体时,这变得繁琐且难以处理。我希望能够基于部分匹配来进行替换。在下面的示例中,我通过直接指定来替换"Spaniard"和"Colombian"的变体。但是,我希望能够根据"Spa"或"Col"存在于单词中的条件来进行这些替换。
library(tidyverse)
library(stringr)

data <- c(
  "Spanish",
  "SPANIARD",
  "Spainiard",
  "Colombian",
  "Columbian",
  "Ecuador",
  "Equador",
  "Ecuadorian",
  "VENEZUELAN"
)

str_replace_all(data,
                c(
                  "Spanish" = "Spaniard",
                  "SPANIARD" = "Spaniard",
                  "Spainiard" = "Spaniard",
                  "Columbian" = "Colombian"
                ))
#> [1] "Spaniard"   "Spaniard"   "Spaniard"   "Colombian"  "Colombian" 
#> [6] "Ecuador"    "Equador"    "Ecuadorian" "VENEZUELAN"

最初的回答: str_replace_all() 的功能如其所述,但我正在寻找在tidyverse中优化此过程的方法。非常感谢您的任何帮助。

创建于2019-05-21,使用reprex包(v0.2.1)

2个回答

3

我倾向于使用距离度量(例如Jaro-Winkler距离或其他距离度量),但它们确实有缺点。要小心部分匹配可能会改变什么。如果您正在进行部分匹配,最好先查看可能性。但是,您可以使用tidyverse中的case_whenstartsWithgrepl来执行您概述的操作:

最初的回答:我推荐使用距离度量,但是要小心部分匹配可能会产生的影响。如果您需要进行部分匹配,请先考虑所有可能性。使用tidyverse中的case_whenstartsWithgrepl即可执行您所描述的操作。
tibble(data = data) %>%
  mutate(
    v1 = tolower(data),
    new_name = case_when(
      startsWith(v1, "spa") ~ "Spanaird",
      startsWith(v1, "col") ~ "Colombian",
      startsWith(v1, "eq") | startsWith(v1, "ec") ~ "Equadorian",
      startsWith(v1, "ven") ~ "Venezuelan",
      TRUE ~ as.character(data)))

# A tibble: 9 x 3
  data       v1         new_name  
  <chr>      <chr>      <chr>     
1 Spanish    spanish    Spanaird  
2 SPANIARD   spaniard   Spanaird  
3 Spainiard  spainiard  Spanaird  
4 Colombian  colombian  Colombian 
5 Columbian  columbian  Colombian 
6 Ecuador    ecuador    Equadorian
7 Equador    equador    Equadorian
8 Ecuadorian ecuadorian Equadorian
9 VENEZUELAN venezuelan Venezuelan

您可以通过以下方式(或其他方式)了解可能性:

最初的回答:

tibble(data = data) %>%
  arrange(data) %>%
  count(tolower(data)) 

1
我刚刚了解到距离度量的概念的存在。有什么建议可以教我如何在R中应用它吗? - undefined
1
嘿 @ChrisAguilar,我会从 stringdist 的文档开始,RecordLinkage 中也有几个距离度量方法。除此之外,我没有太多建议,只能推荐你查阅他们引用的论文或维基百科。很抱歉我帮不上更多忙,祝你好运! - undefined

1
一种选择是使用距离方法进行部分匹配。
vals <- c("Spaniard", "Equador", "Colombian", "Venezuelan")
library(stringdist)
vals[amatch(tolower(data), tolower(vals),maxDist=5)]
#[1] "Spaniard"   "Spaniard"   "Spaniard"   "Colombian"  "Colombian"  
#[6] "Equador"    "Equador"    "Equador"    "Venezuelan"

它可以在 tidyverse 工作流中进行管道传输

library(tidyverse)
tibble(v1 = data) %>%
    mutate(v1 = vals[amatch(tolower(v1), tolower(vals), maxDist = 5)])

通过简单地创建一个包含所需值的字符向量,并像上面一样应用amatch()函数,就可以实现纠正。这太棒了!但是,这种方法有没有什么缺点?或者在哪些常见情况下它会失效?谢谢。 - undefined
1
@ChrisAguilar 是的。它是基于距离方法的,所以如果你的匹配元素变化太大,那么你可能需要增加 maxDist 的值。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接