Bagaimana cara menghapus semua kecuali satu catatan duplikat tertentu dalam bingkai data R? [Tutup]


16

Saya memiliki bingkai data yang berisi beberapa id duplikat. Saya ingin menghapus catatan dengan id duplikat, hanya menjaga baris dengan nilai maksimum.

Jadi untuk terstruktur seperti ini (variabel lain tidak diperlihatkan):

id var_1
1 2
1 4
2 1
2 3
3 5
4 2

Saya ingin menghasilkan ini:

id var_1
1 4
2 3
3 5
4 2

Saya tahu tentang unik () dan digandakan (), tetapi saya tidak tahu cara memasukkan aturan maksimalisasi ...


Ini sebenarnya harus dalam stackoverflow karena ini adalah tugas murni yang berhubungan dengan pemrograman dan tidak ada hubungannya dengan statistik
Penggemar

Jawaban:


24

Salah satu caranya adalah membalikkan data dan menggunakannya duplicateduntuk menjatuhkan semua duplikat. Bagi saya, metode ini secara konsep lebih sederhana daripada yang digunakan berlaku. Saya pikir itu harus sangat cepat juga.

# Some data to start with:
z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
# id var
#  1   2
#  1   4
#  2   1
#  2   3
#  3   5
#  4   2

# Reverse sort
z <- z[order(z$id, z$var, decreasing=TRUE),]
# id var
#  4   2
#  3   5
#  2   3
#  2   1
#  1   4
#  1   2

# Keep only the first row for each duplicate of z$id; this row will have the
# largest value for z$var
z <- z[!duplicated(z$id),]

# Sort so it looks nice
z <- z[order(z$id, z$var),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

Sunting: Saya baru menyadari bahwa penyortir terbalik di atas bahkan tidak perlu disortir idsama sekali. Anda bisa menggunakan z[order(z$var, decreasing=TRUE),]saja dan itu akan berfungsi dengan baik.

Satu lagi pemikiran ... Jika varkolom itu numerik, maka ada cara sederhana untuk mengurutkan sehingga idnaik, tetapi varmenurun. Ini menghilangkan kebutuhan untuk menyortir di akhir (dengan asumsi Anda bahkan ingin diurutkan).

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))

# Sort: id ascending, var descending
z <- z[order(z$id, -z$var),]

# Remove duplicates
z <- z[!duplicated(z$id),]
# id var
#  1   4
#  2   3
#  3   5
#  4   2

1
Pendekatan ini secara signifikan lebih cepat daripada "split-compute-rbind". Selain itu memungkinkan pengelompokan pada lebih dari satu faktor. Untuk a. 650.000 baris (8, sempit, kolom) pendekatan "diduplikasi pesanan" membutuhkan waktu 55 detik, split-compute-rbind ... 1h15minutes. Tentu saja ketika perhitungan agregat selain memilih atau memfilter duplikat, pendekatan yang terakhir atau pendekatan berbasis plyr serupa diperlukan.
mjv

7

Anda sebenarnya ingin memilih elemen maksimum dari elemen dengan id yang sama. Untuk itu Anda bisa menggunakan ddplydari plyr paket :

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
> ddply(dt,.(id),summarise,var_1=max(var))
   id var_1
1  1   4
2  2   3
3  3   4
4  4   2

uniquedan duplicateduntuk menghapus rekaman duplikat, dalam kasus Anda, Anda hanya memiliki id duplikat, bukan catatan.

Pembaruan: Ini adalah kode ketika ada variabel tambahan:

> dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2),bu=rnorm(6))
> ddply(dt,~id,function(d)d[which.max(d$var),])

Bagaimana jika ada variabel lain: bagaimana Anda membawanya?
Aniko

Kami tidak memindahkan pertanyaan seperti itu - terlalu terburu-buru untuk mendapatkan terlalu sedikit.

6

Solusi base-R akan melibatkan split, seperti ini:

z<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))
do.call(rbind,lapply(split(z,z$id),function(chunk) chunk[which.max(chunk$var),]))

splitmemecah frame data menjadi daftar potongan, di mana kami melakukan pemotongan ke baris tunggal dengan nilai maksimal dan kemudian do.call(rbind,...)mengurangi daftar baris tunggal ke dalam bingkai data lagi.


1
Dan seperti biasa ini sekitar 2x lebih cepat dari versi plyr.

1
@ MBb, ya, alami, tetapi jika Anda termasuk biaya debug, untuk data biasa mengatur kecepatan yang dihasilkan adalah sama :) plyr didedikasikan bukan untuk kecepatan, tetapi untuk kejelasan dan kenyamanan.
mpiktas

dan menggunakan ave dua kali lebih cepat :)
Eduardo Leoni

2
@Eduardo aveadalah pembungkus lapply+ split, periksa kode (-;

1
@ Eduardo Ya, tapi itu semua hanya bekerja karena kemungkinan unik penyortiran vektor dalam faktor menggunakan order; untuk masalah yang lebih umum splittidak bisa dihindari.

5

Saya lebih suka menggunakan ave

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,3,3,4,2))
## use unique if you want to exclude duplicate maxima
unique(subset(dt, var==ave(var, id, FUN=max)))

+1, tidak tahu tentang ave. Kapan itu muncul di R?
mpiktas

1

Namun cara lain untuk melakukan ini dengan basis:

dt<-data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,4,2))

data.frame(id=sort(unique(dt$var)),max=tapply(dt$var,dt$id,max))
  id max
1  1   4
2  2   3
3  3   4
4  4   2

Saya lebih suka solusi plyr mpiktas 'sekalipun.


1

Jika, seperti pada contoh, kolom var sudah dalam urutan menaik, kita tidak perlu mengurutkan bingkai data. Kami hanya menggunakan fungsi yang duplicatedmelewati argumen fromLast = TRUE, jadi duplikasi dianggap dari sisi sebaliknya, menjaga elemen terakhir:

z <- data.frame(id=c(1,1,2,2,3,4),var=c(2,4,1,3,5,2))
z[!duplicated(z$id, fromLast = TRUE), ]

  id var
2  1   4
4  2   3
5  3   5
6  4   2

Kalau tidak, kita mengurutkan frame data dalam urutan naik terlebih dahulu:

z <- z[order(z$id, z$var), ]
z[!duplicated(z$id, fromLast = TRUE), ]

Menggunakan dplyrpaket:

library(dplyr)
z %>%
  group_by(id) %>%
  summarise(var = max(var))

Source: local data frame [4 x 2]    
  id var
1  1   4
2  2   3
3  3   5
4  4   2
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.