在data.table中查找*all*重复记录(不是全部而是一个)

Vas*_*y A 29 r data.table

如果我理解正确,duplicated()函数data.table返回一个逻辑向量,它不包含第一次出现的重复记录.标记第一次出现的最佳方法是什么?在这种情况下base::duplicated(),我只是通过与逆序函数分离来解决这个问题:myDups <- (duplicated(x) | duplicated(x, fromLast=TRUE))- 但是data.table::duplicated(),fromLast=TRUE不包括在内(我不知道为什么)......

PS好的,这是一个原始的例子

myDT <- fread(
"id,fB,fC
 1, b1,c1
 2, b2,c2
 3, b1,c1
 4, b3,c3
 5, b1,c1
")
setkeyv(myDT, c('fB', 'fC'))
myDT[, fD:=duplicated(myDT)]
Run Code Online (Sandbox Code Playgroud)

第1,3和5行都是重复的,但只有3和5将被包括在内,duplicated而我需要标记所有这些.

UPD.重要提示:我在下面接受的答案仅适用于键控表.如果要查找考虑所有列的重复记录,则必须setkey明确显示所有这些列.到目前为止,我专门针对这种情况使用以下解决方法:

dups1 <- duplicated(myDT);
dups2 <- duplicated(myDT, fromLast=T);
dups <- dups1 | dups2;
Run Code Online (Sandbox Code Playgroud)

edd*_*ddi 14

许多年前,这是最快的答案(如果感兴趣,请参阅修订历史):

dups = duplicated(myDT, by = key(myDT));
myDT[, fD := dups | c(tail(dups, -1), FALSE)]
Run Code Online (Sandbox Code Playgroud)

从那时起,已经有很多内部变化,但是对于相同的顺序做了很多选择:

myDT <- data.table(id = sample(1e6), 
                   fB = sample(seq_len(1e3), size= 1e6, replace=TRUE), 
                   fC = sample(seq_len(1e3), size= 1e6,replace=TRUE ))
setkey(myDT, fB, fC)

microbenchmark(
   key=myDT[, fD := .N > 1, by = key(myDT)],
   unique=myDT[unique(myDT, by = key(myDT)),fD:=.N>1], 
   dup = myDT[,fD := duplicated.data.frame(.SD)|duplicated.data.frame(.SD, fromLast=TRUE),
              .SDcols = key(myDT)],
   dup2 = {dups = duplicated(myDT, by = key(myDT)); myDT[, fD := dups | c(tail(dups, -1L), FALSE)]},
   dup3 = {dups = duplicated(myDT, by = key(myDT)); myDT[, fD := dups | c(dups[-1L], FALSE)]},
   times=10)

#   expr       min        lq      mean    median        uq       max neval
#    key  523.3568  567.5372  632.2379  578.1474  678.4399  886.8199    10
# unique  189.7692  196.0417  215.4985  210.5258  224.4306  290.2597    10
#    dup 4440.8395 4685.1862 4786.6176 4752.8271 4900.4952 5148.3648    10
#   dup2  143.2756  153.3738  236.4034  161.2133  318.1504  419.4082    10
#   dup3  144.1497  150.9244  193.3058  166.9541  178.0061  460.5448    10
Run Code Online (Sandbox Code Playgroud)

  • 哇,真棒!如果我理解正确,这里我们使用的事实是,在`setkey`之后我们的副本被分组,所以我们可以简单地将我们的`duplicated'向量"移位"一个位置 - 是不是? (3认同)
  • (不确定是否有人可以注意到这些旧帖子的评论) - 我刚刚意识到所有这些方法仅适用于键控表,即如果我想要包括所有要比较的列,我必须明确键入所有这些.如果我错了,请纠正我. (3认同)

mri*_*rip 13

这似乎有效:

> myDT[unique(myDT),fD:=.N>1]
> myDT
   id  fB fC    fD
1:  1  b1 c1  TRUE
2:  3  b1 c1  TRUE
3:  5  b1 c1  TRUE
4:  2  b2 c2 FALSE
5:  4  b3 c3 FALSE
Run Code Online (Sandbox Code Playgroud)

感谢@flodel,更好的方法是:

> myDT[, fD := .N > 1, by = key(myDT)]
> myDT
   id  fB fC    fD
1:  1  b1 c1  TRUE
2:  3  b1 c1  TRUE
3:  5  b1 c1  TRUE
4:  2  b2 c2 FALSE
5:  4  b3 c3 FALSE
Run Code Online (Sandbox Code Playgroud)

效率差异很大:

> microbenchmark(
    key=myDT[, fD := .N > 1, by = key(myDT)],
    unique=myDT[unique(myDT),fD:=.N>1])
Unit: microseconds
   expr      min       lq    median        uq       max neval
    key  679.874  715.700  735.0575  773.7595  1825.437   100
 unique 1417.845 1485.913 1522.7475 1567.9065 24053.645   100
Run Code Online (Sandbox Code Playgroud)

特别是对于最大.那里发生了什么?


mne*_*nel 7

第三种方法(对于这个小例子看来效率更高)

你可以明确地打电话duplicated.data.frame....

myDT[,fD := duplicated.data.frame(.SD)|duplicated.data.frame(.SD, fromLast=TRUE),
  .SDcols = key(myDT)]


 microbenchmark(
   key=myDT[, fD := .N > 1, by = key(myDT)],
   unique=myDT[unique(myDT),fD:=.N>1], 
  dup = myDT[,fD := duplicated.data.frame(.SD)|duplicated.data.frame(.SD, fromLast=TRUE), 
    .SDcols = key(myDT)])
## Unit: microseconds
##    expr      min        lq   median        uq       max neval
##     key  556.608  575.9265  588.906  600.9795 27713.242   100
##  unique 1112.913 1164.8310 1183.244 1216.9000  2263.557   100
##     dup  420.173  436.3220  448.396  461.3750   699.986   100
Run Code Online (Sandbox Code Playgroud)

如果我们扩大样本的大小data.table,那么该key方法是明显的赢家

 myDT <- data.table(id = sample(1e6), 
  fB = sample(seq_len(1e3), size= 1e6, replace=TRUE), 
  fC = sample(seq_len(1e3), size= 1e6,replace=TRUE ))
setkeyv(myDT, c('fB', 'fC'))

microbenchmark(
  key=myDT[, fD := .N > 1, by = key(myDT)],
  unique=myDT[unique(myDT),fD:=.N>1], 
  dup = myDT[,fD := duplicated.data.frame(.SD)|duplicated.data.frame(.SD, fromLast=TRUE),
   .SDcols = key(myDT)],times=10)
## Unit: milliseconds
##    expr       min        lq    median        uq       max neval
##     key  355.9258  358.1764  360.7628  450.9218  500.8360    10
##  unique  451.3794  458.0258  483.3655  519.3341  553.2515    10
##     dup 1690.1579 1721.5784 1775.5948 1826.0298 1845.4012    10
Run Code Online (Sandbox Code Playgroud)


Ale*_*lex 6

从data.table 1.9.8版本开始,eddi的解决方案需要修改为:

dups = duplicated(myDT, by = key(myDT));
myDT[, fD := dups | c(tail(dups, -1), FALSE)]
Run Code Online (Sandbox Code Playgroud)

自从:

v1.9.8 中的更改(在 CRAN 2016 年 11 月 25 日)

潜在的突破性变化

默认情况下,所有列现在都由 unique()、duplicated() 和 uniqueN() data.table 方法使用,#1284 和 #1841。恢复旧行为:options(datatable.old.unique.by.key=TRUE)。在 1 年内,此恢复旧默认值的选项将被弃用并发出警告。2 年后,该选项将被删除。为清楚起见,请明确传递 by=key(DT)。只有依赖于默认值的代码会受到影响。在发布前检查了使用 data.table 的 266 个 CRAN 和 Bioconductor 包。9 需要更改并收到通知。这些检查将遗漏任何没有测试覆盖率的代码行。未检查任何不在 CRAN 或 Bioconductor 上的包裹。