【问题标题】:R - Regex matching on elements in character stringR - 字符串中元素的正则表达式匹配
【发布时间】:2019-08-20 17:38:34
【问题描述】:

我想知道字符串中的任何元素是否出现在其他字符串中。

我的数据包含数百万行,并且是以下模拟数据的结构:

dt <- data.table(product = c("A", "B", "C", "A,C,E", "A,B", "A,B,C", "D", "A", "B", "A", "A", "A,B,C", "D", "D"),
              stock = c("A", "A,B", "A,B,C", "A,B,C,E", "A,B,C,E", "A,B,C,E", "A,B,C,D,E", "A", "A,B", "A,B", "A", "A,B,C", "A,B,C,D", "A,B,C,D"), stringsAsFactors = F)


dt[, product.2 := shift(product, type = "lead")]
dt[, product.3 := shift(product, n = 2, type = "lead")]

> dt
product     stock product.2 product.3
 1:       A         A         B         C
 2:       B       A,B         C     A,C,E
 3:       C     A,B,C     A,C,E       A,B
 4:   A,C,E   A,B,C,E       A,B     A,B,C
 5:     A,B   A,B,C,E     A,B,C         D
 6:   A,B,C   A,B,C,E         D         A
 7:       D A,B,C,D,E         A         B
 8:       A         A         B         A
 9:       B       A,B         A         A
10:       A       A,B         A     A,B,C
11:       A         A     A,B,C         D
12:   A,B,C     A,B,C         D         D
13:       D   A,B,C,D         D      <NA>
14:       D   A,B,C,D      <NA>      <NA>

从这些数据中我想知道以下几点:

  1. 如果product.3 中的任何元素(以comma 分隔)出现在product.2
  2. 如果product.3 中的任何元素(由comma 分隔)未出现在stock 中。
  3. product.3 中的所有元素(由comma 分隔)是否都出现在stock 中?

预期的结果是这样的:

> dt
product     stock product.2 product.3 outcome1 outcome2 outcome3
 1:       A         A         B         C    FALSE    FALSE    FALSE
 2:       B       A,B         C     A,C,E     TRUE     TRUE    FALSE
 3:       C     A,B,C     A,C,E       A,B     TRUE     TRUE     TRUE
 4:   A,C,E   A,B,C,E       A,B     A,B,C     TRUE     TRUE     TRUE
 5:     A,B   A,B,C,E     A,B,C         D    FALSE    FALSE    FALSE
 6:   A,B,C   A,B,C,E         D         A    FALSE     TRUE     TRUE
 7:       D A,B,C,D,E         A         B    FALSE     TRUE     TRUE
 8:       A         A         B         A    FALSE     TRUE     TRUE
 9:       B       A,B         A         A     TRUE     TRUE     TRUE
10:       A       A,B         A     A,B,C     TRUE     TRUE    FALSE
11:       A         A     A,B,C         D    FALSE    FALSE    FALSE
12:   A,B,C     A,B,C         D         D     TRUE    FALSE    FALSE
13:       D   A,B,C,D         D      <NA>    FALSE    FALSE    FALSE
14:       D   A,B,C,D      <NA>      <NA>    FALSE    FALSE    FALSE

此问题是 Stackoverflow 上 this 问题的一部分。

EDIT 08/20/2019:包括第三个预期结果。

【问题讨论】:

    标签: r regex


    【解决方案1】:
    library(data.table)
    library(stringr)
    

    根据?str_detect

    矢量化字符串和模式。等效于 grepl(pattern, x)。 grep(pattern, x) 的等价物参见 str_which()。

    因此,一种选择是将, 替换为|(或匹配项),并直接将'product.2' 的相应元素与'product.3' 进行比较,类似于'product.2' 上的'stock' 比较。 3'。然后,将NA 元素替换为FALSEset

    dt[, outcome1 := str_detect(product.2, str_replace_all(product.3, ",", "|"))]
    dt[, outcome2 := str_detect(stock, str_replace_all(product.3, ",", "|"))]
    for(j in names(dt)[5:6]) set(dt, i = which(is.na(dt[[j]])), j = j, value = FALSE)
    dt
    #    product     stock product.2 product.3 outcome1 outcome2
    # 1:       A         A         B         C    FALSE    FALSE
    # 2:       B       A,B         C     A,C,E     TRUE     TRUE
    # 3:       C     A,B,C     A,C,E       A,B     TRUE     TRUE
    # 4:   A,C,E   A,B,C,E       A,B     A,B,C     TRUE     TRUE
    # 5:     A,B   A,B,C,E     A,B,C         D    FALSE    FALSE
    # 6:   A,B,C   A,B,C,E         D         A    FALSE     TRUE
    # 7:       D A,B,C,D,E         A         B    FALSE     TRUE
    # 8:       A         A         B         A    FALSE     TRUE
    # 9:       B       A,B         A         A     TRUE     TRUE
    #10:       A       A,B         A     A,B,C     TRUE     TRUE
    #11:       A         A     A,B,C         D    FALSE    FALSE
    #12:   A,B,C     A,B,C         D         D     TRUE    FALSE
    #13:       D   A,B,C,D         D      <NA>    FALSE    FALSE
    #14:       D   A,B,C,D      <NA>      <NA>    FALSE    FALSE
    

    前两行代码可以简化为@d.b提到的

    dt[, paste0("outcome", 1:2) := lapply(.SD, str_detect, 
     pattern = str_replace_all(product.3, ",", "|")), .SDcols = c("product.2", "stock")]
    

    更新

    随着 OP 问题的更新

    dt[, paste0("outcome", 1:2) := lapply(.SD, function(x) 
         str_detect(product.3, str_replace_all(x, ",", "|"))), 
              .SDcols = c('product.2', 'stock')]
    dt[, outcome3 :=unlist(Map(function(x, y) {
           x1 <- sort(x[!is.na(x)])
           y1 <- sort(y[!is.na(y)]);
           length(intersect(x1, y1)) == length(x1)},
           str_extract_all(product.3, "[A-Z]"), 
           str_extract_all(stock, "[A-Z]"))) & !is.na(product.3)]
    
    for(j in names(dt)[5:6]) set(dt, i = which(is.na(dt[[j]])), j = j, value = FALSE)
    dt
    #    product     stock product.2 product.3 outcome1 outcome2 outcome3
    # 1:       A         A         B         C    FALSE    FALSE    FALSE
    # 2:       B       A,B         C     A,C,E     TRUE     TRUE    FALSE
    # 3:       C     A,B,C     A,C,E       A,B     TRUE     TRUE     TRUE
    # 4:   A,C,E   A,B,C,E       A,B     A,B,C     TRUE     TRUE     TRUE
    # 5:     A,B   A,B,C,E     A,B,C         D    FALSE    FALSE    FALSE
    # 6:   A,B,C   A,B,C,E         D         A    FALSE     TRUE     TRUE
    # 7:       D A,B,C,D,E         A         B    FALSE     TRUE     TRUE
    # 8:       A         A         B         A    FALSE     TRUE     TRUE
    # 9:       B       A,B         A         A     TRUE     TRUE     TRUE
    #10:       A       A,B         A     A,B,C     TRUE     TRUE    FALSE
    #11:       A         A     A,B,C         D    FALSE    FALSE    FALSE
    #12:   A,B,C     A,B,C         D         D     TRUE    FALSE    FALSE
    #13:       D   A,B,C,D         D      <NA>    FALSE    FALSE    FALSE
    #14:       D   A,B,C,D      <NA>      <NA>    FALSE    FALSE    FALSE
    

    【讨论】:

    • 太棒了! str_detect中的xpattern不应该切换吗?
    • 您对列出的 3 个问题有什么想法吗(根据您的原始答案编辑)
    • 抱歉,没机会看。我离开了
    【解决方案2】:

    split product.3 逗号,然后使用grepl 检查它是否存在于product.2stock

    temp = strsplit(dt$product.3, ",")
    sapply(seq_along(temp), function(i){
        any(sapply(temp[[i]], function(x) grepl(x, dt$product.2[i])))
    })
    # [1] FALSE  TRUE  TRUE  TRUE FALSE FALSE FALSE FALSE  TRUE  TRUE FALSE
    #[12]  TRUE    NA    NA
    sapply(seq_along(temp), function(i){
        any(sapply(temp[[i]], function(x) grepl(x, dt$stock[i])))
    })
    # [1] FALSE  TRUE  TRUE  TRUE FALSE  TRUE  TRUE  TRUE  TRUE  TRUE FALSE
    #[12] FALSE    NA    NA
    

    【讨论】:

    • 考虑到对grepl的调用,这种方法是否可以很好地扩展
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-05
    • 2013-12-25
    • 1970-01-01
    相关资源
    最近更新 更多