【问题标题】:R - extract elements from character string that NOT match other stringR - 从字符串中提取与其他字符串不匹配的元素
【发布时间】:2019-09-06 16:49:47
【问题描述】:

我想从一个字符串中提取不是在另一个字符串中的元素。

最快的(矢量化?)方法是什么?

模拟数据:

library(data.table)
dt <- data.table(id = c("A", "B", "C", "D"),
             product= c("1", "1,2", "1,2,3", "4"),
             stock= c("2, 3", "1,2", "1,2", "4"))

> dt
   id product stock
1:  A       1  2, 3
2:  B     1,2   1,2
3:  C   1,2,3   1,2
4:  D       4     4

我正在寻找的是一个名为new 的新变量,它包含product 中不在stock 中的元素。

> dt
   id product stock  new
1:  A       1  2, 3    1
2:  B     1,2   1,2 <NA>
3:  C   1,2,3   1,2    3
4:  D       4     4 <NA>

注意:它似乎与stringr::str_extract_all 完全相反,但是这个函数没有negate 函数。

【问题讨论】:

  • transform(dt,new = mapply(gsub,gsub(',','|,|',dt$stock),'',dt$product,USE.NAMES = F)) 从基础 R 或使用 dt%&gt;%mutate(new = str_replace_all(product,gsub(',','|,|',stock),''))tidyverse

标签: r regex data.table stringr


【解决方案1】:

这是一种选择,通过使用strssplit 拆分感兴趣的列,使用setdiff 查找不在第二个中的元素。如果没有值,即如果 length 为 0,则返回 NA

f1 <- function(x, y) {
    x1 <- setdiff(x, y)
   if(!length(x1)) NA_character_ else x1
 }

dt[, new := do.call(Map, c(f = f1,
    unname(lapply(.SD, strsplit, ",")))), .SDcols = 2:3]
dt
#   id product stock  new
#1:  A       1  2, 3    1
#2:  B     1,2   1,2 <NA>
#3:  C   1,2,3   1,2    3
#4:  D       4     4 <NA>

或者如果我们需要使用str_extract_all,tidyverse 选项将是

library(tidyverse)
dt %>% 
   mutate_at(2:3, list(newvar = ~ str_extract_all(., '\\d+'))) %>%  
   transmute(id, product, stock, new = map2(product_newvar, stock_newvar, f1))

【讨论】:

  • 对我的实际数据的子集 (nrow==100000) 使用第一种方法时,我遇到了以下错误:Supplied 91336 items to be assigned to 91299 items of column 'new' 这是因为new 中可能有多个元素吗?
  • @wake_wake。这是因为unlist。如果有多个元素返回,请将其保留为列表,以 pastetoString dt[, new := do.call(Map, c(f = f1, unname(lapply(.SD, strsplit, ",")))), .SDcols = 2:3]
  • @wake_wake 在更新中,我删除了unlist,所以它现在应该是list
  • 要让它不上市,我认为可以简单地做dt$new &lt;- sapply(dt$new, toString)
  • @wake_wake 或者可以在函数x1 &lt;- toString(setdiff(x, y))的较早步骤中执行此操作,然后执行较早的unlist版本
【解决方案2】:

仅使用 basedata.table,我们并行循环遍历两列并使用 setdiff,然后添加 NA 并使其成为原子向量:

dt[,new:= mapply(setdiff, strsplit(product, ","), strsplit(stock, ","))]
is.na(dt$new) <- !lengths(dt$new)
dt$new <- unlist(dt$new)
dt
#>    id product stock new
#> 1:  A       1  2, 3   1
#> 2:  B     1,2   1,2  NA
#> 3:  C   1,2,3   1,2   3
#> 4:  D       4     4  NA

这里是纯 data.table 代码:

dt[,new:= mapply(setdiff, strsplit(product, ","), strsplit(stock, ","))][
  lengths(new) == 0, new := NA][
    , new := unlist(new)]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多