Chcem vytvoriť zoskupený filter pomocou dplyr
, tak, že v každej skupine sa vráti len ten riadok, ktorý má minimálnu hodnotu premennej x
.
Môj problém je: Ako sa očakávalo, v prípade viacerých minimá všetko sa vrátia riadky s minimálnou hodnotou. Ale v mojom prípade, Chcem len prvý riadok ak sú prítomné viaceré minimá.
Tu je príklad:
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))
Podľa očakávaní sa vrátia všetky minimá:
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
S ddply, tak by som sa k tejto úlohe blížil takto:
library(plyr)
ddply(df, .(A), function(z) {
z[z$x == min(z$x), ][1, ]
})
... ktorý funguje:
A x y
1 A 1 -1.04584335
2 B 2 0.79600971
3 C 5 -0.08655151
Otázka: Existuje spôsob, ako sa k tomu dostať v dplyre? (Z dôvodov rýchlosti)
odpovede:
66 pre odpoveď č. 1aktualizovať
Pri dplyr> = 0,3 môžete použiť slice
funkcia v kombinácii s which.min
, čo by bol môj obľúbený prístup k tejto úlohe:
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
Pôvodná odpoveď
Pre vzorové dáta je možné použiť aj dve filter
po sebe navzájom:
group_by(df, A) %>%
filter(x == min(x)) %>%
filter(1:n() == 1)
27 pre odpoveď č. 2
Len pre úplnosť: Tu je finále dplyr
riešenie, odvodené z pripomienok @hadley a @Arun:
library(dplyr)
df.g <- group_by(df, A)
filter(df.g, rank(x, ties.method="first")==1)
14 pre odpoveď č. 3
Prečo stojí za to, tu je a data.table
riešenie pre tých, ktorí môžu mať záujem:
# 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 pre odpoveď № 4
To sa dá dosiahnuť použitím row_number
skombinované s group_by
. row_number
spracováva väzby priradením poradia nielen hodnotou, ale aj relatívnym poradím v rámci vektora. Ak chcete získať prvý riadok každej skupiny s minimálnou hodnotou x
:
df.g <- group_by(df, A)
filter(df.g, row_number(x) == 1)
Viac informácií nájdete v dplyr vinety na oknách.
0 pre odpoveď č. 5
Mám rád sqldf pre svoju jednoduchosť ..
sqldf("select A,min(X),y from "df.g" group by A")
Výkon:
A min(X) y
1 A 1 -1.4836989
2 B 2 0.3755771
3 C 5 0.9284441
0 pre odpoveď č. 6
Iný spôsob, ako to urobiť:
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))
výsledok:
a b
1 1 -0.8356286
2 2 -2.2146999
Mohlo by sa tiež ľahko prispôsobiť tak, aby sa v každej skupine získala maximálna hodnota.