首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >从载体中删除类似但较长的重复

从载体中删除类似但较长的重复
EN

Stack Overflow用户
提问于 2017-12-19 19:50:24
回答 4查看 165关注 0票数 3

对于数据库清理,我有一个向量,比如说,碟子,我想删除“基本”盘的所有变体,只保留基本盘。例如,如果我有..。

代码语言:javascript
运行
复制
dishes <- c("DAL BHAT", "DAL BHAT-(SPICY)", "DAL BHAT WITH EXTRA RICE", 
            "HAMBURGER", "HAMBURGER-BIG", "HAMBURGER2", "PIZZA", 
            "PIZZA (PROSCIUTO)", "PIZZA_BOLOGNESE")

..。我想删除所有已经在向量中具有较短匹配版本的条目。由此产生的载体将只包括:"DAL BHAT",“汉堡包”,“比萨饼”。

使用嵌套的for循环并对所有其他内容进行检查对于这个示例来说是可行的,但是对于手头的大型数据集来说,这需要花费很长时间,而且我要说的代码也很难看。

可以假定所有的条目都是大写的,向量已经被排序了。不能假定下一个基本盘的第一项总是比前一项短。

对于如何有效地解决这一问题,有什么建议吗?

奖励问题:理想情况下,我只想删除项目从初始向量,如果他们至少比他们的较短的对应3个字符。在上述情况下,这意味着"HAMBURGER2“也将保留在生成的向量中。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2017-12-30 17:55:01

这是我想用的方法。我会用需要考虑的一些条件创建一个函数,并在输入中使用它。我添加了一些注释来解释函数中发生了什么。

该函数有4个参数:

  • invec:输入字符向量。
  • thresh:我们可以用多少个字符来确定“基本”菜。默认值= 5。
  • minlen:你的“奖金”问题。默认值= 3。
  • strict:合乎逻辑。如果有nchar比你的thresh短的基本菜肴,你想要降低阈值,还是严格要求你的基础?默认值= FALSE。关于strict如何工作,请参见最后一个示例。
代码语言:javascript
运行
复制
myfun <- function(invec, thresh = 5, minlen = 3, strict = FALSE) {
  # Bookkeeping -- sort, unique, all upper case
  invec <- sort(unique(toupper(invec)))
  # More bookkeeping -- min should not be longer 
  # than min base dish unless strict = TRUE
  thresh <- if (isTRUE(strict)) thresh else min(min(nchar(invec)), thresh)
  # Use `thresh` to get the `stubs``
  stubs <- invec[!duplicated(substr(invec, 1, thresh))]
  # loop through the stubs and do two things:
  #   - Match the dish with the stub
  #   - Return the base dish and any dishes within the minlen
  unlist(
    lapply(stubs, function(x) {
      temp <- grep(x, invec, value = TRUE, fixed = TRUE)
      temp[temp == x | nchar(temp) <= nchar(x) + minlen]
      }), 
    use.names = FALSE)
}

你的样本数据:

代码语言:javascript
运行
复制
dishes <- c("DAL BHAT", "DAL BHAT-(SPICY)", "DAL BHAT WITH EXTRA RICE", 
            "HAMBURGER", "HAMBURGER-BIG", "HAMBURGER2", "PIZZA", 
            "PIZZA (PROSCIUTO)", "PIZZA_BOLOGNESE")    

结果如下:

代码语言:javascript
运行
复制
myfun(dishes, minlen = 0)
# [1] "DAL BHAT"  "HAMBURGER" "PIZZA" 

myfun(dishes)
# [1] "DAL BHAT"   "HAMBURGER"  "HAMBURGER2" "PIZZA" 

这是一些更多的样本数据。请注意,在"dishes2“中,数据不再被排序,并且有一个新的项"DAL",而在"dishes3”中,也有小写的菜品。

代码语言:javascript
运行
复制
dishes2 <- c("DAL BHAT", "DAL BHAT-(SPICY)", "DAL BHAT WITH EXTRA RICE", 
             "HAMBURGER", "HAMBURGER-BIG", "HAMBURGER2", "PIZZA", 
             "PIZZA (PROSCIUTO)", "PIZZA_BOLOGNESE", "DAL")

dishes3 <- c("DAL BHAT", "DAL BHAT-(SPICY)", "DAL BHAT WITH EXTRA RICE", 
             "HAMBURGER", "HAMBURGER-BIG", "HAMBURGER2", "PIZZA", 
             "PIZZA (PROSCIUTO)", "PIZZA_BOLOGNESE", "DAL", "pizza!!")

这是向量上的函数:

代码语言:javascript
运行
复制
myfun(dishes2, 4)
# [1] "DAL"        "HAMBURGER"  "HAMBURGER2" "PIZZA"   

myfun(dishes3)
# [1] "DAL"        "HAMBURGER"  "HAMBURGER2" "PIZZA"      "PIZZA!!"  

myfun(dishes3, strict = TRUE)
# [1] "DAL"        "DAL BHAT"   "HAMBURGER"  "HAMBURGER2" "PIZZA"      "PIZZA!!"  
票数 5
EN

Stack Overflow用户

发布于 2017-12-30 18:42:14

OP请求删除向量中已经具有较短匹配版本的所有条目。此外,OP希望从初始向量中删除项,如果它们比较短的向量长至少3个字符。

蛮力方法将尝试比较所有条目,以确定一个字符串是否是另一个字符串的一部分。这将需要n (n-1)比较。

下面的方法试图通过预先检查字符数来减少字符串比较的数量。这至少会使调用grepl()的次数减少一半。

代码语言:javascript
运行
复制
library(data.table)
# prepare data
DT <- data.table(dish = dishes)[, len := nchar(dish)][order(len)]
DT

dish len 1: NAN 3 2: PIZZA 5 3: DAL BHAT 8 4: HAMBURGER 9 5: HAMBURGER2 10 6: HAMBURGER-BIG 13 7: SLICE OF PIZZA 14 8: PIZZA\_BOLOGNESE 15 9: DAL BHAT-(SPICY) 16 10: PIZZA (PROSCIUTO) 17 11: DAL BHAT WITH EXTRA RICE 24

代码语言:javascript
运行
复制
# use non-equi join to find row numbers of "duplicate" entries
tmp <- DT[.(len + 3L, dish), on = .(len > V1), nomatch = 0L, allow = TRUE,
          by = .EACHI, .I[grepl(V2, dish)]]
tmp

len V1 1: 8 7 2: 8 8 3: 8 10 4: 11 9 5: 11 11 6: 12 6

代码语言:javascript
运行
复制
# anti-join to remove "duplicates"
DT[!tmp$V1, dish]

1“南”“比萨饼”“达尔巴特”“汉堡包”"HAMBURGER2“

编辑

由于非equi,此方法也不需要事先重新排序DT

代码语言:javascript
运行
复制
delta_len <- 3L
DT <- data.table(dish = dishes)[, len := nchar(dish)]
DT[!DT[.(len + delta_len, dish), on = .(len > V1), nomatch = 0L, allow = TRUE,
       by = .EACHI, .I[grepl(V2, dish)]]$V1, dish]

1“达尔巴特”“汉堡包”"HAMBURGER2“”比萨饼“"NAN”

这样做的好处是保持了dishes的原始顺序(删除了“重复”)。

数据

代码语言:javascript
运行
复制
dishes <- c("DAL BHAT", "DAL BHAT-(SPICY)", "DAL BHAT WITH EXTRA RICE", 
            "HAMBURGER", "HAMBURGER-BIG", "HAMBURGER2", "PIZZA", 
            "PIZZA (PROSCIUTO)", "PIZZA_BOLOGNESE", "NAN", "SLICE OF PIZZA")

请注意,添加了两个项以涵盖其他测试用例。

票数 2
EN

Stack Overflow用户

发布于 2017-12-30 18:57:13

使用sapplygreplcolSums的一种可能的解决方案

代码语言:javascript
运行
复制
dishes[colSums(sapply(dishes, function(x) grepl(x, setdiff(dishes, x)))) > 0]

这意味着:

1 "DAL BHAT“”汉堡包“”披萨“

这样做的目的是:

  • sapply(dishes, function(x) grepl(x, setdiff(dishes, x)))dishes的每个元素与其他元素进行比较,并使用grepl查看特定元素是否是其他元素的一部分。
  • 这将返回一个逻辑矩阵,其中一个TRUE值指示一个菜名是否是另一个菜名的一部分: 大HAMBURGER2比萨饼PIZZA_BOLOGNESE 1,真假2,真假3,假四假五假六假七假8假
  • 通过使用colSums的列和,可以得到每个菜名包含多少个其他菜名的数字向量: DAL BHAT DAL BHAT -(辛辣) DAL BHAT加额外的大米汉堡汉堡-大HAMBURGER2比萨饼PIZZA_BOLOGNESE 2 0 0 2 0 0 2 0 0
  • 只有较短的菜名的计数大于零。因此,将数字向量与零进行比较,返回要保留的盘子的逻辑向量。
  • 作为使用> 0的另一种选择,您还可以在colSums前面使用双重否定符号(!!)。这还会选择计数不等于零的元素:dishes[!!colSums(sapply(dishes, function(x) grepl(x, setdiff(dishes, x))))]

如果要考虑字符长度的最大差异,则可以使用agrepl而不是grepl,其中可以使用max.distance-parameter指定字符中的最大编辑差异:

代码语言:javascript
运行
复制
dishes[colSums(sapply(dishes, function(x) agrepl(x, setdiff(dishes, x), max.distance = 3))) > 0]

这意味着:

1 "DAL BHAT“”汉堡包“"HAMBURGER2”“披萨”

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/47894225

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档