【问题标题】:Identifying patterns in two strings in R在 R 中识别两个字符串中的模式
【发布时间】:2020-12-18 16:50:43
【问题描述】:

我想评估 ColA 是否包含比 ColB 新的字符串。但是,我对某些类型的字符串不感兴趣,例如 oil。我想要一个指标变量如下:

  ColA                           ColB                       Ind
--------------------------      ------------------------   -----
 coconut+grape+pine              grape+coconut              TRUE
 orange+apple+grape+pine         grape+coconut              TRUE
 grape+pine                      grape+oil                  TRUE
 oil+grape                       grape+apple                FALSE
 grape                           grape+oil                  FALSE
 grape+pine                      grape+orange+pine          FALSE

对 R 有什么建议吗?

非常感谢!

【问题讨论】:

    标签: r split string-matching


    【解决方案1】:

    由于我们需要拆分字符串,我们将从strsplit开始,

    strsplit(dat$ColA, '+', fixed = TRUE)
    # [[1]]
    # [1] "coconut" "grape"   "pine"   
    # [[2]]
    # [1] "orange" "apple"  "grape"  "pine"  
    # [[3]]
    # [1] "grape" "pine" 
    # [[4]]
    # [1] "oil"   "grape"
    # [[5]]
    # [1] "grape"
    # [[6]]
    # [1] "grape" "pine" 
    

    从这里,我们想确定ColA 中的内容是什么,而不是ColB 中的内容。我将使用Map 在每个集合上运行setdiffColA[[1]]ColB[[1]] 等)。

    Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE))
    # [[1]]
    # [1] "pine"
    # [[2]]
    # [1] "orange" "apple"  "pine"  
    # [[3]]
    # [1] "pine"
    # [[4]]
    # [1] "oil"
    # [[5]]
    # character(0)
    # [[6]]
    # character(0)
    

    要确定哪个有“新词”,我们可以使用lengths(.) > 0检查非零长度:

    lengths(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE))) > 0
    # [1]  TRUE  TRUE  TRUE  TRUE FALSE FALSE
    

    但由于您不关心 oil,我们也需要删除它。

    lapply(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE)), setdiff, "oil")
    # [[1]]
    # [1] "pine"
    # [[2]]
    # [1] "orange" "apple"  "pine"  
    # [[3]]
    # [1] "pine"
    # [[4]]
    # character(0)
    # [[5]]
    # character(0)
    # [[6]]
    # character(0)
    lengths(lapply(Map(setdiff, strsplit(dat$ColA, '+', fixed = TRUE), strsplit(dat$ColB, '+', fixed = TRUE)),
                   setdiff, "oil")) > 0
    # [1]  TRUE  TRUE  TRUE FALSE FALSE FALSE
    

    @akrun 提出了一个 tidyverse 变体:

    library(dplyr)
    library(purrr)   # map2_lgl
    library(stringr) # str_extract_all
    dat %>%
      mutate(
        new = map2_lgl(
          str_extract_all(ColB, "\\w+"), str_extract_all(ColA, "\\w+"),
          ~ !all(setdiff(.y, "oil") %in% .x)
        )
      )
    #                      ColA              ColB   Ind   new
    # 1      coconut+grape+pine     grape+coconut  TRUE  TRUE
    # 2 orange+apple+grape+pine     grape+coconut  TRUE  TRUE
    # 3              grape+pine         grape+oil  TRUE  TRUE
    # 4               oil+grape       grape+apple FALSE FALSE
    # 5                   grape         grape+oil FALSE FALSE
    # 6              grape+pine grape+orange+pine FALSE FALSE
    

    数据

    dat <- structure(list(ColA = c("coconut+grape+pine", "orange+apple+grape+pine", "grape+pine", "oil+grape", "grape", "grape+pine"), ColB = c("grape+coconut", "grape+coconut", "grape+oil", "grape+apple", "grape+oil", "grape+orange+pine"), Ind = c(TRUE, TRUE, TRUE, FALSE, FALSE, FALSE)), class = "data.frame", row.names = c(NA, -6L))
    

    【讨论】:

    • 一个tidyverse选项是df1 %&gt;% mutate(new = map2_lgl(str_extract_all(ColB, "\\w+"), str_extract_all(ColA, "\\w+"), ~ !all(setdiff(.y, "oil") %in% .x)))
    【解决方案2】:

    这是一个类似于r2evans's 的解决方案,它在do.call 的帮助下只调用一次strsplit

    rid <- function(x) x[!x %in% z]  ## helper FUN to get rid of the oil
    
    z <- "oil"
    L <- sapply(unname(dat), strsplit, "\\+")
    dat$ind <- sapply(1:nrow(L), function(x) length(do.call(setdiff, rev(Map(rid, L[x,]))))) > 0
    dat
    #                  V1                      V2   ind
    # 1     grape+coconut      coconut+grape+pine  TRUE
    # 2     grape+coconut orange+apple+grape+pine  TRUE
    # 3         grape+oil              grape+pine  TRUE
    # 4       grape+apple               oil+grape FALSE
    # 5         grape+oil                   grape FALSE
    # 6 grape+orange+pine              grape+pine FALSE
    

    数据:

    dat <- structure(list(V1 = c("grape+coconut", "grape+coconut", "grape+oil", 
    "grape+apple", "grape+oil", "grape+orange+pine"), V2 = c("coconut+grape+pine", 
    "orange+apple+grape+pine", "grape+pine", "oil+grape", "grape", 
    "grape+pine")), row.names = c(NA, -6L), class = "data.frame")
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-09
      • 2021-04-01
      • 2015-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多