2014-06-16 24 views
54

Chciałbym wybrać wiersz z maksymalną wartością w każdej grupie z dplyr.Jak wybrać wiersze z wartościami maksymalnymi w każdej grupie za pomocą dplyr?

pierwsze wygenerować losowe dane, aby pokazać moje pytanie

set.seed(1) 
df <- expand.grid(list(A = 1:5, B = 1:5, C = 1:5)) 
df$value <- runif(nrow(df)) 

W plyr, mogę użyć funkcji niestandardowej, aby wybrać ten wiersz.

library(plyr) 
ddply(df, .(A, B), function(x) x[which.max(x$value),]) 

W dplyr używam tego kodu, aby uzyskać maksymalną wartość, ale nie wierszy z maksymalną wartością (kolumna C w tym przypadku).

library(dplyr) 
df %>% group_by(A, B) %>% 
    summarise(max = max(value)) 

Jak mogę to osiągnąć? Dzięki za wszelkie sugestie.

sessionInfo() 
R version 3.1.0 (2014-04-10) 
Platform: x86_64-w64-mingw32/x64 (64-bit) 

locale: 
[1] LC_COLLATE=English_Australia.1252 LC_CTYPE=English_Australia.1252 
[3] LC_MONETARY=English_Australia.1252 LC_NUMERIC=C      
[5] LC_TIME=English_Australia.1252  

attached base packages: 
[1] stats  graphics grDevices utils  datasets methods base  

other attached packages: 
[1] dplyr_0.2 plyr_1.8.1 

loaded via a namespace (and not attached): 
[1] assertthat_0.1.0.99 parallel_3.1.0  Rcpp_0.11.1   
[4] tools_3.1.0   

Odpowiedz

64

Spróbuj tego:

result <- df %>% 
      group_by(A, B) %>% 
      filter(value == max(value)) %>% 
      arrange(A,B,C) 

wydaje się działać:

identical(
    as.data.frame(result), 
    ddply(df, .(A, B), function(x) x[which.max(x$value),]) 
) 
#[1] TRUE 

Jak podkreślił @docendo w komentarzach, slice może być tutaj korzystne, gdyż za odpowiedź @RoyalITS”poniżej jeśli chcesz tylko 1 wiersz na grupę. Ta odpowiedź zwróci wiele wierszy, jeśli istnieje wiele z identyczną wartością maksymalną.

+11

Wyniki są identyczne w tym przypadku, ponieważ nie występują powielone wartości maksymalne. W przeciwnym razie metoda 'filter' zwróci wszystkie wartości maksymalne (wiersze) na grupę, podczas gdy podejście OP z opcją' which.max' zwróci tylko jeden maksimum (pierwszy) na grupę. Aby powielić to zachowanie, inną opcją jest użycie 'slice (which.max (value))' w dplyr. –

40

Można użyć top_n

df %>% group_by(A, B) %>% top_n(n=1) 

Będzie rangi od ostatniej kolumnie (value) i powrót z najlepszymi n=1 wiersze.

Obecnie nie można zmienić to ustawienie domyślne, nie powodując błąd (Zobacz https://github.com/hadley/dplyr/issues/426)

29
df %>% group_by(A,B) %>% slice(which.max(value)) 
7

Ten bardziej gadatliwy rozwiązanie zapewnia większą kontrolę nad tym co się dzieje w przypadku duplikatu maksymalnej wartości (w tym przykładzie, zajmie losowo jeden z odpowiednich wierszy)

library(dplyr) 
df %>% group_by(A, B) %>% 
    mutate(the_rank = rank(-value, ties.method = "random")) %>% 
    filter(the_rank == 1) %>% select(-the_rank)