Manchmal muss ich nur die erste Zeile eines Datensatzes abrufen, der nach einem Bezeichner gruppiert ist, z. B. beim Abrufen von Alter und Geschlecht, wenn mehrere Beobachtungen pro Person vorliegen. Was ist ein schneller (oder der schnellste) Weg, dies in R zu tun? Ich habe aggregate () unten verwendet und vermute, dass es bessere Möglichkeiten gibt. Bevor ich diese Frage postete, suchte ich ein bisschen bei Google, fand und probierte ddply und war überrascht, dass es extrem langsam war und mir Speicherfehler in meinem Datensatz (400.000 Zeilen x 16 Spalten, 7.000 eindeutige IDs) und in der aggregate () -Version bescherte war einigermaßen schnell.
(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: Siehe Chases Antwort und Matt Parkers Kommentar zu dem, was ich für den elegantesten Ansatz halte. Die schnellste Lösung, die das data.table
Paket verwendet, finden Sie in der Antwort von @Matthew Dowle .
quelle
diff()
damit Sie die erste ID in auswählen könnendx
.Antworten:
Ist Ihre ID-Spalte wirklich ein Faktor? Wenn es tatsächlich numerisch ist, können Sie die
diff
Funktion zu Ihrem Vorteil nutzen. Sie könnten es auch zwingen, mit zu numerischas.numeric()
.quelle
dx[c(TRUE, dx$ID[-1] != dx$ID[-length(dx$ID)], ]
für nicht numerische Daten tun - ich erhalte 0,03 für Zeichen, 0,05 für Faktoren. PS:)
In Ihrer erstensystem.time()
Funktion gibt es ein Extra , nach der zweiten Null.data.table
Lösung unten sollte sich als die schnellste herausstellen, also würde ich das überprüfen, wenn ich Sie wäre (es sollte wahrscheinlich die akzeptierte Antwort hier sein).Nach der Antwort von Steve gibt es in data.table einen viel schnelleren Weg:
Wenn Sie lediglich die erste Zeile jeder Gruppe benötigen, können Sie sich viel schneller direkt an diese Zeile anschließen. Warum sollte das SD-Objekt jedes Mal erstellt werden, um nur die erste Zeile zu verwenden?
Vergleichen Sie die 0.064 von data.table mit "Matt Parkers Alternative zu Chases Lösung" (die bisher die schnellste zu sein schien):
Also ~ 5 mal schneller, aber es ist ein winziger Tisch mit weniger als 1 Million Zeilen. Mit zunehmender Größe nimmt auch der Unterschied zu.
quelle
[.data.table
Funktion werden kann ... Ich glaube, ich habe nicht gemerkt, dass Sie kein.SD
Objekt erstellt haben, wenn Sie es nicht wirklich brauchten. Schön!dxt <- data.table(dx, key='ID')
system.time () aufrufen, ist dies schneller als die @ Matt-Lösung.SD[1L]
vollständig optimiert wurden und die Antwort von @SteveLianoglou für 5e7-Zeilen doppelt so schnell wäre.Sie brauchen nicht mehrere
merge()
Schritte, nuraggregate()
beide Variablen von Interesse:Vergleichszeitpunkte:
1) Matts Lösung:
2) Zachs Reshape2-Lösung:
3) Steve's data.table Lösung:
4) Chases schnelle Lösung unter Verwendung von Zahlen und nicht von Faktoren
ID
:und 5) Matt Parkers Alternative zu Chases Lösung für Charakter oder Faktor
ID
, die etwas schneller ist als Chases numerische LösungID
:quelle
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
s so dass das Ergebnis mit anderen Lösungen vergleichbar war.Sie können versuchen, das Paket data.table zu verwenden .
Für Ihren speziellen Fall ist der Vorteil, dass es (wahnsinnig) schnell ist. Als ich zum ersten Mal darauf aufmerksam wurde, arbeitete ich an data.frame-Objekten mit Hunderttausenden von Zeilen. "Normal"
aggregate
oderddply
Methoden wurden ~ 1-2 Minuten in Anspruch genommen (dies war, bevor Hadley dasidata.frame
Mojo einführteddply
). Verwendendata.table
war die Operation buchstäblich in wenigen Sekunden erledigt.Der Nachteil ist, dass es so schnell ist, weil es Ihre data.table (es ist wie ein data.frame) nach "Schlüsselspalten" sortiert und eine intelligente Suchstrategie verwendet, um Teilmengen Ihrer Daten zu finden. Dies führt zu einer Neuordnung Ihrer Daten, bevor Sie Statistiken darüber sammeln.
Vorausgesetzt, Sie möchten nur die erste Zeile jeder Gruppe - möglicherweise wird die Neuordnung die erste Zeile durcheinander bringen, weshalb dies in Ihrer Situation möglicherweise nicht angemessen ist.
Wie auch immer, Sie müssen hier beurteilen, ob dies
data.table
angemessen ist oder nicht , aber so würden Sie es mit den Daten verwenden, die Sie präsentiert haben:Update: Matthew Dowle (der Hauptentwickler des data.table-Pakets) bietet eine bessere / intelligentere / (extrem) effizientere Möglichkeit, data.table zur Lösung dieses Problems zu verwenden .
quelle
Versuchen Sie es mit reshape2
quelle
Du könntest es versuchen
Ich habe jedoch keine Ahnung, ob dies schneller sein
plyr
wird.quelle