Terkadang saya hanya perlu mendapatkan baris pertama dari kumpulan data yang dikelompokkan berdasarkan pengidentifikasi, seperti saat mengambil usia dan jenis kelamin saat ada beberapa pengamatan per individu. Apa cara cepat (atau tercepat) untuk melakukan ini di R? Saya menggunakan agregat () di bawah dan curiga ada cara yang lebih baik. Sebelum memposting pertanyaan ini saya mencari sedikit di google, menemukan dan mencoba ddply, dan terkejut bahwa itu sangat lambat dan memberi saya kesalahan memori pada dataset saya (400.000 baris x 16 cols, 7.000 ID unik), sedangkan versi agregat () cukup cepat.
(dx <- data.frame(ID = factor(c(1,1,2,2,3,3)), AGE = c(30,30,40,40,35,35), FEM = factor(c(1,1,0,0,1,1))))
# ID AGE FEM
# 1 30 1
# 1 30 1
# 2 40 0
# 2 40 0
# 3 35 1
# 3 35 1
ag <- data.frame(ID=levels(dx$ID))
ag <- merge(ag, aggregate(AGE ~ ID, data=dx, function(x) x[1]), "ID")
ag <- merge(ag, aggregate(FEM ~ ID, data=dx, function(x) x[1]), "ID")
ag
# ID AGE FEM
# 1 30 1
# 2 40 0
# 3 35 1
#same result:
library(plyr)
ddply(.data = dx, .var = c("ID"), .fun = function(x) x[1,])
UPDATE: Lihat jawaban Chase dan komentar Matt Parker untuk apa yang saya anggap sebagai pendekatan yang paling elegan. Lihat jawaban @Matthew Dowle untuk solusi tercepat yang menggunakan data.table
paket.
sumber
diff()
sehingga Anda dapat mengambil ID pertamadx
.Jawaban:
Apakah kolom ID Anda benar-benar faktor? Jika ini sebenarnya numerik, saya pikir Anda dapat menggunakan
diff
fungsi ini untuk keuntungan Anda. Anda juga bisa memaksa ke numerikas.numeric()
.sumber
dx[c(TRUE, dx$ID[-1] != dx$ID[-length(dx$ID)], ]
untuk data non-numerik - Saya mendapatkan 0,03 untuk karakter, 0,05 untuk faktor. PS: ada tambahan)
disystem.time()
fungsi pertama Anda , setelah nol kedua.data.table
solusi di bawah harus membuktikan menjadi yang tercepat, jadi saya akan memeriksa bahwa jika aku jadi kau (mungkin harus menjadi jawaban diterima di sini).Menindaklanjuti jawaban Steve, ada cara yang jauh lebih cepat dalam data.tabel:
Jika Anda hanya membutuhkan baris pertama dari setiap grup, itu jauh lebih cepat untuk bergabung ke baris itu secara langsung. Mengapa membuat objek .SD setiap kali, hanya menggunakan baris pertama saja?
Bandingkan 0,064 data. Tabel untuk "Alternatif Matt Parker untuk solusi Chase" (yang tampaknya menjadi yang tercepat sejauh ini):
Jadi ~ 5 kali lebih cepat, tapi meja kecil di bawah 1 juta baris. Ketika ukuran bertambah, begitu pula perbedaannya.
sumber
[.data.table
fungsi itu bisa ... Saya kira saya tidak menyadari Anda tidak membuat.SD
objek jika Anda tidak benar-benar membutuhkannya. Yang bagus!dxt <- data.table(dx, key='ID')
dalam panggilan ke system.time (), itu lebih cepat daripada solusi @ Matt.SD[1L]
sepenuhnya dioptimalkan dan sebenarnya @SteveLianoglou jawaban akan dua kali lebih cepat untuk baris 5e7.Anda tidak perlu beberapa
merge()
langkah, cukupaggregate()
kedua variabel yang diminati:Pengaturan waktu perbandingan:
1) solusi Matt:
2) solusi pembentukan kembali Zach:
3) solusi data.table Steve:
4) Chase solusi cepat menggunakan numerik, bukan faktor,
ID
:dan 5) alternatif Matt Parker untuk solusi Chase, untuk karakter atau faktor
ID
, yang sedikit lebih cepat daripada yang numerik ChaseID
:sumber
dx$ID <- sample(as.numeric(dx$ID)) #assuming IDs arent presorted system.time(replicate(1000, { dy <- dx[order(dx$ID),] dy[ diff(c(0,dy$ID)) != 0, ] })) user system elapsed 0.58 0.00 0.58
ID
sehingga hasilnya sebanding dengan solusi lain.Anda dapat mencoba menggunakan paket data.table .
Untuk kasus khusus Anda, kelebihannya adalah (gila) cepat. Pertama kali saya diperkenalkan dengannya, saya mengerjakan objek data.frame dengan ratusan ribu baris. "Normal"
aggregate
atauddply
metode diambil ~ 1-2 menit untuk menyelesaikan (ini sebelum Hadley memperkenalkanidata.frame
mojo ke dalamddply
). Menggunakandata.table
, operasi secara harfiah dilakukan dalam hitungan detik.Kelemahannya adalah hal itu sangat cepat karena akan menggunakan data Anda. Tabel (seperti halnya data.frame) dengan "kolom kunci" dan menggunakan strategi pencarian cerdas untuk menemukan himpunan bagian dari data Anda. Ini akan menghasilkan penataan ulang data Anda sebelum Anda mengumpulkan statistik.
Mengingat bahwa Anda hanya ingin baris pertama dari setiap grup - mungkin pemesanan ulang akan mengacaukan baris yang pertama, itulah sebabnya mungkin tidak sesuai untuk situasi Anda.
Bagaimanapun, Anda harus menilai apakah
data.table
pantas atau tidak di sini, tetapi ini adalah bagaimana Anda akan menggunakannya dengan data yang Anda sajikan:Pembaruan: Matthew Dowle (pengembang utama paket data.table) telah menyediakan cara yang lebih baik / lebih pintar / (sangat) lebih efisien untuk menggunakan data.tabel untuk memecahkan masalah ini sebagai salah satu jawaban di sini ... pasti periksa .
sumber
Coba bentuk ulang2
sumber
Kamu bisa mencoba
Saya tidak tahu apakah ini akan menjadi lebih cepat daripada
plyr
.sumber