Come selezionare le righe con i valori massimi in ciascun gruppo con dplyr?

Vorrei selezionare una riga con il valore massimo in ogni gruppo con dplyr.

In primo luogo, generi alcuni dati casuali per mostrare la mia domanda

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

In plyr, potrei usare una funzione personalizzata per selezionare questa riga.

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

In dplyr, sto usando questo codice per ottenere il valore massimo, ma non le righe con valore massimo (colonna C in questo caso).

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

Come potrei ottenere questo? Grazie per qualsiasi suggerimento.

 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 

Prova questo:

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

Sembra funzionare:

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

Come sottolineato da @docendo nei commenti, qui può essere preferita la sezione come per la risposta di @RoyalITS in basso se si desidera solo 1 riga per gruppo. Questa risposta restituirà più righe se ci sono più di un valore massimo identico.

Puoi usare top_n

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

Questo verrà classificato dall’ultima colonna ( value ) e restituirà il primo n=1 righe.

Attualmente, non è ansible modificare questo valore predefinito senza causare errori (vedere https://github.com/hadley/dplyr/issues/426 )

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

Questa soluzione più verbosa offre un maggiore controllo su ciò che accade in caso di valore massimo duplicato (in questo esempio, prenderà una delle righe corrispondenti casualmente)

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