过滤出data.table中的重复/非唯一行


77

编辑2019: 在2016年11月进行更改之前,曾问过这个问题data.table,有关当前方法和以前的方法,请参见下面可接受的答案。

我有一个data.table约250万行的表。有两列。我想删除在两列中都重复的任何行。以前对于data.frame我会这样做: df -> unique(df[,c('V1', 'V2')])但这对data.table不起作用。我已经尝试过,unique(df[,c(V1,V2), with=FALSE])但是它似乎仍然只对data.table的键进行操作,而不是对整个行进行操作。

有什么建议么?

欢呼声,戴维

>dt
      V1   V2
[1,]  A    B
[2,]  A    C
[3,]  A    D
[4,]  A    B
[5,]  B    A
[6,]  C    D
[7,]  C    D
[8,]  E    F
[9,]  G    G
[10,] A    B

在上面的data.table中,其中V2的表键是,仅删除行4,7和10。

> dput(dt)
structure(list(V1 = c("B", "A", "A", "A", "A", "A", "C", "C", 
"E", "G"), V2 = c("A", "B", "B", "B", "C", "D", "D", "D", "F", 
"G")), .Names = c("V1", "V2"), row.names = c(NA, -10L), class = c("data.table", 
"data.frame"), .internal.selfref = <pointer: 0x7fb4c4804578>, sorted = "V2")

3
不使用唯一dt[, .N,by=.(V1,V2)][,1:2]
Akki

Answers:


95

适用于v1.9.8 +2016年11月发布

?unique.data.table 默认状态开始,所有列都在使用(与一致?unique.data.frame

unique(dt)
   V1 V2
1:  A  B
2:  A  C
3:  A  D
4:  B  A
5:  C  D
6:  E  F
7:  G  G

或使用by参数来获取特定列的唯一组合(例如以前的键用于)

unique(dt, by = "V2")
   V1 V2
1:  A  B
2:  A  C
3:  A  D
4:  B  A
5:  E  F
6:  G  G

先前的v1.9.8

从中?unique.data.table可以明显看出,调用unique数据表仅对键起作用。这意味着您必须在调用之前将键重置为所有列unique

library(data.table)
dt <- data.table(
  V1=LETTERS[c(1,1,1,1,2,3,3,5,7,1)],
  V2=LETTERS[c(2,3,4,2,1,4,4,6,7,2)]
)

unique以一列为键进行调用:

setkey(dt, "V2")
unique(dt)
     V1 V2
[1,]  B  A
[2,]  A  B
[3,]  A  C
[4,]  A  D
[5,]  E  F
[6,]  G  G


1
仅在未设置任何键的情况下才有效。我将编辑上面的问题以使其清楚。抱歉
戴维·卡瓦纳

2
akrun在这里回答:stackoverflow.com/questions/40949023/…第一个版本现在需要使用by =选项才能工作
Peter Pan

@PeterPan您发布的链接已死
wolfsatthedoor

16
@Peter指出,@ Andrie此解决方案不再起作用。data.table不再考虑unique()按键。unique(, by = c(keys))现在必须使用该选项。
altabq

4
让我们知道altabq是正确的,并且密钥中的内容必须用引号引起来。因此,您需要unique(dt,by = c(“ V1”,“ V2”))作为答案。
Corey Levinson

9

以您的示例数据表为例...

> dt<-data.table(V1 = c("B", "A", "A", "A", "A", "A", "C", "C", "E", "G"), V2 = c("A", "B", "B", "B", "C", "D", "D", "D", "F", "G"))
> setkey(dt,V2)

考虑以下测试:

> haskey(dt) # obviously dt has a key, since we just set it
[1] TRUE

> haskey(dt[,list(V1,V2)]) # ... but this is treated like a "new" table, and does not have a key
[1] FALSE

> haskey(dt[,.SD]) # note that this still has a key
[1] TRUE

因此,您可以列出表的各列,然后使用该列unique(),而无需NULL根据@Andrie(并由@MatthewDowle编辑)的解决方案所需,将键设置为所有列或将其删除(通过将其设置为) )。@Pop和@Rahul建议的解决方案对我不起作用。

请参阅下面的“尝试3”,它与您的最初尝试非常相似。您的示例不清楚,所以我不确定为什么它不起作用。同样是几个月前,您发布了问题,所以也许data.table已经更新了?

> unique(dt) # Try 1: wrong answer (missing V1=C and V2=D)
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  E  F
6:  G  G

> dt[!duplicated(dt)] # Try 2: wrong answer (missing V1=C and V2=D)
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  E  F
6:  G  G

> unique(dt[,list(V1,V2)]) # Try 3: correct answer; does not require modifying key
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  C  D
6:  E  F
7:  G  G

> setkey(dt,NULL)
> unique(dt) # Try 4: correct answer; requires key to be removed
   V1 V2
1:  B  A
2:  A  B
3:  A  C
4:  A  D
5:  C  D
6:  E  F
7:  G  G

3
也许新的unique(...,use.key=FALSE)论点会有所帮助;现在归档为FR#2483
Matt Dowle 2013年

嗨@MatthewDowle。是的,这将是一个很好的便利。我认为您在FR中的评论也是正确的-如果密钥是唯一的,则use.key=FALSE可以忽略。
dnlbrky 2013年

1
data.table 1.9.6(无疑是早期版本)具有by=可用于覆盖键的选项。设置by=NULL“使用所有列,并且行为类似data.frame方法。”
JWilliman


1

这应该为你工作

dt <- unique(dt, by = c('V1', 'V2'))

1
OP希望删除整个数据表行中的重复行,而不仅仅是键。这应该做到这一点。
岩浆

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.