【问题标题】:R: Replace string when partial match to another column by rowR:当部分匹配到另一列时替换字符串
【发布时间】:2022-01-07 01:08:09
【问题描述】:

我想替换/删除与我的数据表中其他列(statecity)匹配的字符串(name)部分。

我设法识别了行,例如与城市,像这样: dt%>% filter(str_detect(name, city)) 但我缺少一种将gsub(或grep)与城市列的行值一起使用的方法。

我知道一种相当手动的方法,例如将所有城市名称存储在一个向量中并将它们输入gsub 会起作用,但它也会错误地删除第 2 行的“达拉斯”。(尽管这对于各州来说是可以管理的,并且可以与 gsub 结合也可以删除“of”。)


数据和期望的输出

dt<- data.table(city = c("arecibo","arecibo","cabo rojo", "new york", "dallas"), 
state=c("pr", "pr", "pr", "ny", "tx"), 
name=c("frutas of pr arecibo", "dallas frutas of pr", "cabo rojo metal plant", "greens new york", "cowboy shoes dallas tx"), 
desired=c("frutas", "dallas frutas", "metal plant", "greens", "cowboy shoes"))

【问题讨论】:

    标签: r dplyr data.table


    【解决方案1】:

    data.table 解决方案:

    # Helper function
    subxy <-  function(string, rmv) mapply(function(x, y) sub(x, '', y), rmv, string)
    
    dt[,  desired2 := name |> subxy(city) |> subxy(state) |> subxy('of') |> trimws()]
    
    #         city state                   name       desired      desired2
    # 1:   arecibo    pr   frutas of pr arecibo        frutas        frutas
    # 2:   arecibo    pr    dallas frutas of pr dallas frutas dallas frutas
    # 3: cabo rojo    pr  cabo rojo metal plant   metal plant   metal plant
    # 4:  new york    ny        greens new york        greens        greens
    # 5:    dallas    tx cowboy shoes dallas tx  cowboy shoes  cowboy shoes
    

    【讨论】:

    • @Magasinus 您使用的是旧版本的 R,但为了缓解问题,您可以将 \(x, y) 替换为 function(x,y)
    • |&gt; 使用magrittr 管道%&gt;%
    • 这个解决方案很棒,但在应用于真实数据时也有同样的问题:它还会清除以州缩写开头的真实姓名。有没有比subxy &lt;- function(string, rmv) mapply(function(x, y) sub(paste(" ",x," ",sep=""), '', paste(" ",y," ",sep="")), rmv, string) 更优雅的方法来解决这个问题,这真的能起到作用吗?
    • @Magasinus 您可以通过在州名之前要求空格来考虑这一点,只需将subxy()paste0(' ', state) 一起输入。
    【解决方案2】:

    这是一个解决方案,但使用gsub 方法可能会更快地实现。无论如何:

    library(tidyverse)
    
    
      dt %>% 
      mutate(test = str_remove_all(name,city)) %>% 
      mutate(test = str_remove_all(test,paste(" of ",state,sep=""))) %>% 
      mutate(test = str_remove_all(test,state)) %>% 
      mutate(test = str_remove_all(test,"^ ")) %>% 
      mutate(test = str_remove_all(test," *$"))
    

    输出:

            city state                   name       desired          test
    1:   arecibo    pr   frutas of pr arecibo        frutas        frutas
    2:   arecibo    pr    dallas frutas of pr dallas frutas dallas frutas
    3: cabo rojo    pr  cabo rojo metal plant   metal plant   metal plant
    4:  new york    ny        greens new york        greens        greens
    5:    dallas    tx cowboy shoes dallas tx  cowboy shoes  cowboy shoes
    

    【讨论】:

    • 我们可以将它组合起来以仅在后面跟一个空格和state 时替换“of”吗?
    • 当然,查看编辑@Magasinus
    • 对于真实数据,我们必须小心给定像“ma”这样的状态。建议使用mutate(test = str_remove_all(test,paste(" ",state," ", sep=""))
    【解决方案3】:

    使用 dplyr,我们可以使用rowwise。首先使用 OR 元字符将要删除的所有单词折叠成单个字符元素(如'arecibo|pr|of'),然后使用该模式调用str_remove_all。 最后,删除剩余的空格。

    library(dplyr)
    library(stringr)
    
    dt %>%
        rowwise()%>%
        mutate(desired_2 = str_remove_all(name, paste(c(city, state, 'of'), collapse = '|'))%>%
                   trimws())
    
    # A tibble: 5 × 5
    # Rowwise: 
      city      state name                   desired       desired_2    
      <chr>     <chr> <chr>                  <chr>         <chr>        
    1 arecibo   pr    frutas of pr arecibo   frutas        frutas       
    2 arecibo   pr    dallas frutas of pr    dallas frutas dallas frutas
    3 cabo rojo pr    cabo rojo metal plant  metal plant   metal plant  
    4 new york  ny    greens new york        greens        greens       
    5 dallas    tx    cowboy shoes dallas tx cowboy shoes  cowboy shoes 
    

    【讨论】:

    • 对不起,我们必须使用rowwise 来实现,我最初使用它,但最终被删除。现在好了。请立即测试更新后的答案。
    猜你喜欢
    • 2023-02-16
    • 2015-11-03
    • 2016-09-14
    • 2021-07-11
    • 1970-01-01
    • 2014-06-26
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    相关资源
    最近更新 更多