Фільтрування повторених / не унікальних рядків у data.table


79

Редагувати 2019: це питання було задано до змін у data.tableлистопаді 2016 року; див. Прийняту відповідь нижче як для поточного, так і для попередніх методів.

У мене є data.tableтаблиця приблизно з 2,5 мільйонами рядків. Є дві колонки. Я хочу видалити всі рядки, які дублюються в обох стовпцях. Раніше для 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

Відповіді:


99

Для v1.9.8 + ( випущено листопад 2016 р. )

Від ?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

Попередня версія 1.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
Це працює, лише якщо жодна клавіша не встановлена. Я відредагую вищезазначене питання, щоб це було зрозуміло. Вибачте
Davy Kavanagh

2
як отвеченние тут akrun: stackoverflow.com/questions/40949023 / ... перша версія тепер вимагає від = варіанти для роботи
Якоб

@PeterPan посилання, яке ви опублікували, мертве
wolfsatthedoor

16
@Andrie це рішення вже не працює, як зазначив @PeterPan. data.tableбільше не враховує unique()в ключах. Опцію unique(, by = c(keys))потрібно використовувати зараз.
altabq

4
Нехай буде відомо, що altabq має рацію, і речі в ключах повинні бути оточені лапками. Отже, ви хочете отримати унікальну (dt, by = c ("V1", "V2")) як свою відповідь.
Кори Левінсон,

9

З вашим прикладом data.table ...

> 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

Привіт @MatthewDowle. Так, це було б приємною зручністю. Я думаю, що ваш коментар у FR також правильний - якщо ключ унікальний, його use.key=FALSEможна проігнорувати.
dnlbrky

1
data.table 1.9.6 (і, без сумніву, попередні версії), має опцію, by=яка може бути використана для заміни ключа. Параметр by=NULL"використовує всі стовпці і діє як аналогічні методи data.frame."
JWilliman


1

Це має працювати для вас

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

1
OP хоче видалити повторені рядки з цілого рядка таблиці даних, на відміну від лише ключа. Це має зробити те.
Магма

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.