2014-07-03 12 views
21

Attualmente ho un problema come segue. In un set di dati in cui esistono più osservazioni per ogni soggetto e voglio creare un sottoinsieme di questo set di dati in cui sono selezionati solo i dati massimi per un record. Ad esempio, per un insieme di dati come qui sotto:Come selezionare la riga con il valore massimo in ciascun gruppo

ID <- c(1,1,1,2,2,2,2,3,3) 
Value <- c(2,3,5,2,5,8,17,3,5) 
Event <- c(1,1,2,1,2,1,2,2,2) 

group <- data.frame(Subject=ID, pt=Value, Event=Event) 

Oggetto 1, 2 e 3 hanno rispettivamente il più grande valore pt 5, 17 e 5. Come potrei in primo luogo, trovare il più grande valore di pt per ogni soggetto, e poi mettere questa osservazione in un altro frame di dati? Ciò significa che questo sottoinsieme avrebbe solo i valori pt più alti per ogni soggetto.

+0

Questo è molto vicino, ma per un minimo invece di massima http://stackoverflow.com/questions/24070714/extract-row-corresponding-to-minimum-value- di-a-variabile per gruppo –

+0

Correlati: [Sottoinsieme per gruppo con data.table] (https://stackoverflow.com/questions/16573995/subset-by-group-with-data-table) – Henrik

risposta

44

Ecco una soluzione data.table:

require(data.table) ## 1.9.2 
group <- as.data.table(group) 

Se si desidera mantenere tutte le voci corrispondenti ai valori massimi di pt all'interno di ciascun gruppo:

group[group[, .I[pt == max(pt)], by=Subject]$V1] 
# Subject pt Event 
# 1:  1 5  2 
# 2:  2 17  2 
# 3:  3 5  2 

Se vuoi solo il primo valore massimo di pt:

group[group[, .I[which.max(pt)], by=Subject]$V1] 
# Subject pt Event 
# 1:  1 5  2 
# 2:  2 17  2 
# 3:  3 5  2 

In questo caso, non fa la differenza, in quanto vi sono valori massimi non più all'interno di ogni gruppo nei tuoi dati

+1

visto che data.table ha avuto un sacco di cambiamenti dal 2014, è ancora la soluzione più veloce/migliore per questa domanda? – Ben

+1

@ Ben, in questo caso, la risposta più veloce è ancora questa, sì. L'ottimizzazione di '.SD' per questi casi è ancora nella lista. Tieni d'occhio [# 735] (https://github.com/Rdatatable/data.table/issues/735). – Arun

+3

Ciao, Cos'è $ V1 qui? #noob –

5

non ero sicuro di quello che si voleva fare sulla colonna Evento, ma se si vuole mantenere anche quello, come su

isIDmax <- with(dd, ave(Value, ID, FUN=function(x) seq_along(x)==which.max(x)))==1 
group[isIDmax, ] 

# ID Value Event 
# 3 1  5  2 
# 7 2 17  2 
# 9 3  5  2 

Qui usiamo ave a guardare la colonna "Valore" per ogni "ID". Quindi determiniamo quale valore è il massimo e quindi lo trasformiamo in un vettore logico che possiamo utilizzare per suddividere l'originale data.frame.

+0

Grazie mille ma ho un'altra domanda qui.Perché usare con la funzione in questo metodo dato che (Value, ID, FUN = function (x) seq_along (x) == which.max (x)) == 1 funziona estremamente bene? Sono un po 'confuso. –

+0

Ho usato 'with' perché è un po 'strano avere i dati disponibili sia all'interno che all'esterno di' group' data.frame. Se leggi i dati con 'read.table' o qualcosa del genere, dovresti usare' with' perché quei nomi di colonna non sarebbero disponibili al di fuori di data.frame. – MrFlick

2

Una soluzione dplyr:

> library(dplyr) 
> ID <- c(1,1,1,2,2,2,2,3,3) 
> Value <- c(2,3,5,2,5,8,17,3,5) 
> Event <- c(1,1,2,1,2,1,2,2,2) 
> group <- data.frame(Subject=ID, pt=Value, Event=Event) 
> group <- group_by(group, Subject) 
> summarize(group, max.pt = max(pt)) 

Questo produce il seguente frame di dati:

Subject max.pt 
1  1  5 
2  2  17 
3  3  5 
+5

Penso che l'OP voglia mantenere la colonna 'Event' nel sottoinsieme nel qual caso potresti fare:' df%>% group_by (Subject)%>% filter (pt == max (pt)) '(include i legami se presente) –

15

Una soluzione più breve usando data.table:

setDT(group)[, .SD[which.max(pt)], by=Subject] 
# Subject pt Event 
# 1:  1 5  2 
# 2:  2 17  2 
# 3:  3 5  2 
22

Il metodo più intuitivo è quello di utilizzare group_by e la funzione top_n in dplyr

group %>% group_by(Subject) %>% top_n(1, pt) 

Il risultato che si ottiene è

Source: local data frame [3 x 3] 
    Groups: Subject [3] 

     Subject pt Event 
     (dbl) (dbl) (dbl) 
    1  1  5  2 
    2  2 17  2 
    3  3  5  2 
-1

altro l'opzione è slice

library(dplyr) 
group %>% 
    group_by(Subject) %>% 
    slice(which.max(pt)) 
# Subject pt Event 
# <dbl> <dbl> <dbl> 
#1  1  5  2 
#2  2 17  2 
#3  3  5  2 
0
do.call(rbind, lapply(split(group,as.factor(group$Subject)), function(x) {return(x[which.max(x$pt),])})) 

Utilizzando Base R

Problemi correlati