【问题标题】:Tidyverse: Replacing entire strings based on partial matchesTidyverse:根据部分匹配替换整个字符串
【发布时间】:2019-10-08 00:05:51
【问题描述】:

我希望使用 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"

reprex package (v0.2.1) 于 2019 年 5 月 21 日创建

所以str_replace_all() 像宣传的那样工作,但我正在寻找一种方法来简化 tidyverse 中的这个过程。非常感谢任何帮助。

【问题讨论】:

    标签: r tidyverse stringr


    【解决方案1】:

    我更喜欢使用距离度量(例如,Jaro-winkler 距离或其他一些距离度量),但它们确实有其缺点。对部分匹配可能会改变的内容感到厌烦。如果您正在进行部分匹配,那么明智的做法是看看有哪些可能性。但是,您可以使用case_whenstartsWithgrepl 来完成您在tidyverse 中概述的操作:

    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)) 
    

    【讨论】:

    • 我才刚刚了解到距离测量概念的存在。关于如何学习如何在 R 中应用它的任何建议?
    • 嘿@ChrisAguilar,我将从stringdist 的文档开始,RecordLinkage 中也有几个距离度量。除了他们引用的论文/我浏览过的维基百科之外,我没有太多推荐。对不起,我没有更多的帮助,但祝你好运!!!
    【解决方案2】:

    一种选择是使用距离方法进行部分匹配

    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(),即可应用更正。那太棒了!这种方法是否有任何缺点,或者它会失败的常见情况?谢谢。
    • @ChrisAguilar 是的。它是基于距离的方法,所以如果你的匹配元素变化太大,那么你可能需要增加maxDist
    猜你喜欢
    • 1970-01-01
    • 2019-01-30
    • 2020-09-27
    • 1970-01-01
    • 2019-12-10
    • 2020-09-23
    • 1970-01-01
    • 2014-03-22
    • 2023-02-16
    相关资源
    最近更新 更多