【问题标题】:Find repeating groups in r data.table在 r data.table 中查找重复组
【发布时间】:2020-04-28 11:01:26
【问题描述】:

我需要在 r 数据表中识别和去重记录组(但我认为问题在任何编程语言中都是相同的),结构如下:

组由 var1 和 var2 中的值标识,如果它们具有相同的大小并且在 var2 和 var3 中包含相同的值,则它们是重复的(var3 中的值是由 var1 和 var2 标识的较大组的共同点) .

所以在示例中,两个红色组是重复的,但对 (red,blue) 和对 (red,brown) 不是。

我的解决方案是将表格转换为宽格式

然后执行unique(dt[,var1:=NULL]) 并转回长格式(此时我不再需要 var1)。

问题是我的真实表有 165,391,868 条记录,这不是一次性任务,而是每周一次的任务,具有相似大小的表并且时间有限。

我尝试将表拆分成块,附加它们,然后进行重复数据删除,但第一个转置现在已经运行了 2 小时以上!

任何替代和最快的解决方案? 非常感谢!

创建示例表的代码:

dt <- data.table(
var1=c(
    "value1_1",
    "value1_1",
    "value1_1",
    "value1_2",
    "value1_2",
    "value1_2",
    "value1_2",
    "value1_3",
    "value1_3",
    "value1_3",
    "value1_4",
    "value1_4",
    "value1_4",
    "value1_5",
    "value1_5",
    "value1_5",
    "value1_5"),
var2=c(
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1",
    "value2_1"),
var1=c(
    "value3_1",
    "value3_2",
    "value3_3",
    "value3_2",
    "value3_4",
    "value3_5",
    "value3_6",
    "value3_1",
    "value3_2",
    "value3_3",
    "value3_1",
    "value3_2",
    "value3_4",
    "value3_1",
    "value3_2",
    "value3_3",
    "value3_5"))

【问题讨论】:

  • 您的预期输出是什么?只保留绿色、蓝色和棕色的行?
  • 我希望有绿色、蓝色和棕色的线条,而红色的线条只有一次
  • 但是 2 个红色组有不同的 var1 值。它们是如何重复的?
  • 如果你读到他说的重复是基于 var3 列和大小的问题
  • 对不起,要重复它们也需要在 var2 中具有相同的值

标签: r duplicates data.table


【解决方案1】:

这里有 2 个其他选项:

1) 将var3 折叠成单个值以供加入

lu <- dt[, paste(var3, collapse=""), .(var1, var2)]

samegrp <- lu[lu, on=.(V1)][
    var1!=i.var1 & var2==i.var2, 
    .(var1=c(var11, var12), g=.GRP),
    .(var11=pmin(var1, i.var1), var12=pmax(var1, i.var1), var2)]

dt[samegrp, on=.(var1, var2), g := g]

输出:

        var1     var2     var3  g
 1: value1_1 value2_1 value3_1  1
 2: value1_1 value2_1 value3_2  1
 3: value1_1 value2_1 value3_3  1
 4: value1_2 value2_1 value3_2 NA
 5: value1_2 value2_1 value3_4 NA
 6: value1_2 value2_1 value3_5 NA
 7: value1_2 value2_1 value3_6 NA
 8: value1_3 value2_1 value3_1  1
 9: value1_3 value2_1 value3_2  1
10: value1_3 value2_1 value3_3  1
11: value1_4 value2_1 value3_1 NA
12: value1_4 value2_1 value3_2 NA
13: value1_4 value2_1 value3_4 NA
14: value1_5 value2_1 value3_1 NA
15: value1_5 value2_1 value3_2 NA
16: value1_5 value2_1 value3_3 NA
17: value1_5 value2_1 value3_5 NA

2) 匹配次数:

setkey(dt, var1, var2, var3)
count <- dt[, .N, .(var1, var2)]

matches <- dt[dt, on=.(var2, var3), allow.cartesian=TRUE, nomatch=0L][
    var1!=i.var1,
    .(N=.N / 2, g=.GRP),
    .(var11=pmin(i.var1, var1), var12=pmax(i.var1, var1), var2)]

matches[count, on=.(var11=var1, var2, N), nomatch=0L][
    count, on=.(var12=var1, var2, N), nomatch=0L]

输出:

      var11    var12     var2 N g
1: value1_1 value1_3 value2_1 3 1

第二种方法更占用内存,因此可能会更慢。但实际性能确实取决于实际数据集的特性。例如。列的数据类型,var1var2的唯一对数,var3的唯一值数等。

【讨论】:

    【解决方案2】:

    我想我有一个解决方案,但如果它不起作用,请告诉我,我会再次破解。

    我刚刚通过将 var2 添加到 id 列来响应您的评论进行编辑

    首先根据 var1 和 var2 为组创建一个列

    dt[,group:=paste0(var1, var2)]
    

    然后根据 var3 和大小创建一个 id

    dt[,id:=paste0(paste(sort(var3), collapse=""), var2, .N), by=group]
    

    然后,根据您是否第一次、第二次、第三次看到具有该 ID 的组,您可以用一个数字标记每个组

    dt[,groupN:=as.numeric(factor(group)), by=id]
    

    然后只保留你第一次看到每个组的时候

    dt[groupN==1]
    

    【讨论】:

    • 很好用。我现在正在运行它,看看需要多长时间
    • 折叠步骤所花费的时间与转置一样长,所以它对我来说真的不起作用
    • 是的,这似乎是一个耗时的步骤。我很想看看其他人是否有更快的解决方案。
    【解决方案3】:

    这行得通,但我不知道它的效率(老实说,它可能更慢,但它的方法不同)。我已经为另一个项目构建了多重过滤器功能,我突然想到在这里使用它。 multifilter 根据您提供给它的任何列中找到的变量的唯一组合将数据框拆分为数据框列表。然后我们检查重复的 var 3 cols 并删除它们。最后数据集被反弹。

    multifilter <- function(data,filterorder){  
      newdata <- list(data)
      for(i in rev(filterorder)){
        newdata <- unlist(lapply(sort(unique(data[,i])), function(x) lapply(newdata, function(y) y[y[,i]==x,])),recursive=F)
      }
      return(newdata[sapply(newdata,nrow)>=1])
    }
    
    
    filtereddt <- multifilter(dt,c("var1","var2"))
    filtereddt <- filtereddt[-duplicated(lapply(filtereddt, function(x) x[,3]))]
    filtereddt <- do.call(rbind, filtereddt)[,-1]
    

    输出:

    > filtereddt
           var2     var3
    4  value2_1 value3_2
    5  value2_1 value3_4
    6  value2_1 value3_5
    7  value2_1 value3_6
    8  value2_1 value3_1
    9  value2_1 value3_2
    10 value2_1 value3_3
    11 value2_2 value3_1
    12 value2_2 value3_2
    13 value2_2 value3_4
    14 value2_1 value3_1
    15 value2_1 value3_2
    16 value2_1 value3_3
    17 value2_1 value3_5
    

    【讨论】:

    • 我收到一个错误:[.data.table(data, , i) 中的错误:j([...] 中的第二个参数)是单个符号,但未找到列名 'i' .也许您打算使用 DT[, ..i]。与 data.frame 的这种差异是经过深思熟虑的,并在 FAQ 1.1 中进行了解释。我一直在尝试自己修复它,但不能。
    猜你喜欢
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 2013-05-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-10
    相关资源
    最近更新 更多