Chcę użyć zgrupowanego filtra przy użyciu dplyr
, w taki sposób, że w obrębie każdej grupy zwracany jest tylko ten wiersz, który ma minimalną wartość zmiennej x
.
Mój problem: zgodnie z oczekiwaniami, w przypadku wielu minimów wszystko wiersze z minimalną wartością są zwracane. Ale w moim przypadku Chcę tylko pierwszego rzędu jeśli występuje wiele minima.
Oto przykład:
df <- data.frame(
A=c("A", "A", "A", "B", "B", "B", "C", "C", "C"),
x=c(1, 1, 2, 2, 3, 4, 5, 5, 5),
y=rnorm(9)
)
library(dplyr)
df.g <- group_by(df, A)
filter(df.g, x == min(x))
Zgodnie z oczekiwaniami wszystkie minima są zwracane:
Source: local data frame [6 x 3]
Groups: A
A x y
1 A 1 -1.04584335
2 A 1 0.97949399
3 B 2 0.79600971
4 C 5 -0.08655151
5 C 5 0.16649962
6 C 5 -0.05948012
Z ddply, podszedłbym do tego zadania w następujący sposób:
library(plyr)
ddply(df, .(A), function(z) {
z[z$x == min(z$x), ][1, ]
})
... który działa:
A x y
1 A 1 -1.04584335
2 B 2 0.79600971
3 C 5 -0.08655151
P: Czy istnieje sposób podejścia do tego w dplyr? (Ze względu na szybkość)
Odpowiedzi:
66 dla odpowiedzi nr 1Aktualizacja
Przy dplyr> = 0.3 możesz użyć slice
funkcja w połączeniu z which.min
, które byłoby moim ulubionym podejściem do tego zadania:
df %>% group_by(A) %>% slice(which.min(x))
#Source: local data frame [3 x 3]
#Groups: A
#
# A x y
#1 A 1 0.2979772
#2 B 2 -1.1265265
#3 C 5 -1.1952004
Oryginalna odpowiedź
Dla przykładowych danych możliwe jest również użycie dwóch filter
po sobie:
group_by(df, A) %>%
filter(x == min(x)) %>%
filter(1:n() == 1)
27 dla odpowiedzi nr 2
Tylko dla kompletności: Oto finał dplyr
rozwiązanie, pochodzące z komentarzy @hadley i @Arun:
library(dplyr)
df.g <- group_by(df, A)
filter(df.g, rank(x, ties.method="first")==1)
14 dla odpowiedzi nr 3
Za to, co jest warte, tutaj jest data.table
rozwiązanie, dla tych, którzy mogą być zainteresowani:
# approach with setting keys
dt <- as.data.table(df)
setkey(dt, A,x)
dt[J(unique(A)), mult="first"]
# without using keys
dt <- as.data.table(df)
dt[dt[, .I[which.min(x)], by=A]$V1]
2 dla odpowiedzi № 4
Można to osiągnąć za pomocą row_number
w połączeniu z group_by
. row_number
obsługuje powiązania, przypisując rangę nie tylko wartością, ale także względną kolejnością w wektorze. Aby uzyskać pierwszy wiersz każdej grupy o minimalnej wartości x
:
df.g <- group_by(df, A)
filter(df.g, row_number(x) == 1)
Aby uzyskać więcej informacji zobacz dplyr winieta na funkcje okna.
0 dla odpowiedzi № 5
Lubię sqldf ze względu na jego prostotę ..
sqldf("select A,min(X),y from "df.g" group by A")
Wydajność:
A min(X) y
1 A 1 -1.4836989
2 B 2 0.3755771
3 C 5 0.9284441
0 dla odpowiedzi № 6
Inny sposób na zrobienie tego:
set.seed(1)
x <- data.frame(a = rep(1:2, each = 10), b = rnorm(20))
x <- dplyr::arrange(x, a, b)
dplyr::filter(x, !duplicated(a))
Wynik:
a b
1 1 -0.8356286
2 2 -2.2146999
Można również łatwo dostosować do uzyskania wiersza w każdej grupie o maksymalnej wartości.