Hier ist ein Beispieldatenrahmen:
d <- data.frame(
x = runif(90),
grp = gl(3, 30)
)
Ich möchte die Teilmenge d
der Zeilen mit den Top 5 Werten von x
für jeden Wert von grp
.
Mit base-R wäre mein Ansatz ungefähr so:
ordered <- d[order(d$x, decreasing = TRUE), ]
splits <- split(ordered, ordered$grp)
heads <- lapply(splits, head)
do.call(rbind, heads)
## x grp
## 1.19 0.8879631 1
## 1.4 0.8844818 1
## 1.12 0.8596197 1
## 1.26 0.8481809 1
## 1.18 0.8461516 1
## 1.29 0.8317092 1
## 2.31 0.9751049 2
## 2.34 0.9269764 2
## 2.57 0.8964114 2
## 2.58 0.8896466 2
## 2.45 0.8888834 2
## 2.35 0.8706823 2
## 3.74 0.9884852 3
## 3.73 0.9837653 3
## 3.83 0.9375398 3
## 3.64 0.9229036 3
## 3.69 0.8021373 3
## 3.86 0.7418946 3
Mit dplyr
erwartete ich, dass dies funktioniert:
d %>%
arrange_(~ desc(x)) %>%
group_by_(~ grp) %>%
head(n = 5)
Es werden jedoch nur die gesamten oberen 5 Zeilen zurückgegeben.
Tauschen head
gegen top_n
gibt das ganze zurück d
.
d %>%
arrange_(~ desc(x)) %>%
group_by_(~ grp) %>%
top_n(n = 5)
Wie bekomme ich die richtige Teilmenge?
quelle
Ziemlich einfach mit
data.table
...Oder
Oder (Sollte für große Datenmengen schneller sein, da nicht
.SD
für jede Gruppe angerufen werden muss)Bearbeiten: Hier ist wie im
dplyr
Vergleich zudata.table
(wenn jemand interessiert ist)Hinzufügen einer geringfügig schnelleren
data.table
Lösung:Timing-Ausgabe:
quelle
data.table
Methode, die etwas schneller sein sollte:dt <- setorder(setDT(dd), grp, -x); dt[dt[, .I[seq_len(.N) <= 5L], grp]$V1]
data.table
Methode einfacher hinzufügen:setDT(d)[order(-x),x[1:5],keyby = .(grp)]
:
wird schlagenhead
setorder
schneller alsorder
Sie müssen
head
einen Anruf bei einschließendo
. Stellt im folgenden Code.
die aktuelle Gruppe dar (siehe Beschreibung...
auf derdo
Hilfeseite).Wie von Akrun erwähnt,
slice
ist eine Alternative.Obwohl ich dies der Vollständigkeit
data.table
halber nicht gefragt habe, ist eine mögliche Version (danke an @Arun für das Update):quelle
setDT(d)[order(-x), head(.SD, 5L), by=grp]
~
und verwendenarrange
undgroup_by
anstelle vonarrange_
undgroup_by_
Mein Ansatz in Basis R wäre:
Und mit dplyr ist der Ansatz mit
slice
wahrscheinlich am schnellsten, aber Sie können auch verwenden,filter
was wahrscheinlich schneller ist als mitdo(head(., 5))
:dplyr Benchmark
quelle
filter
erfordert eine zusätzliche Funktion, während Ihreslice
Version nicht ...data.table
haben;)top_n (n = 1) gibt weiterhin mehrere Zeilen für jede Gruppe zurück, wenn die Ordnungsvariable nicht in jeder Gruppe eindeutig ist. Fügen Sie jeder Zeile eine eindeutige Variable hinzu, um genau ein Vorkommen für jede Gruppe auszuwählen:
quelle
Eine weitere
data.table
Lösung, um die prägnante Syntax hervorzuheben:quelle