Agregue un dataframe en una columna determinada y visualice otra columna

Tengo un dataframe en R de la siguiente forma:

> head(data) Group Score Info 1 1 1 a 2 1 2 b 3 1 3 c 4 2 4 d 5 2 3 e 6 2 1 f 

Me gustaría agregarlo siguiendo la columna Score usando la función max

 > aggregate(data$Score, list(data$Group), max) Group.1 x 1 1 3 2 2 4 

Pero también me gustaría mostrar la columna de Info asociada al valor máximo de la columna Score para cada grupo. No tengo ni idea de cómo hacer esto. Mi resultado deseado sería:

  Group.1 xy 1 1 3 c 2 2 4 d 

¿Alguna pista?

Primero, divide los datos usando split :

 split(z,z$Group) 

Luego, para cada fragmento, selecciona la fila con Puntuación máxima:

 lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),]) 

Finalmente reduzca de nuevo a un data.frame do.call ing rbind :

 do.call(rbind,lapply(split(z,z$Group),function(chunk) chunk[which.max(chunk$Score),])) 

Resultado:

  Group Score Info 1 1 3 c 2 2 4 d 

Una línea, sin hechizos mágicos, rápido, el resultado tiene buenos nombres =)

Una solución base R es combinar la salida de aggregate() con un paso merge() . Encuentro que la interfaz de fórmula para aggregate() un poco más útil que la interfaz estándar, en parte porque los nombres en el resultado son más agradables, así que usaré eso:

El paso aggregate() es

 maxs <- aggregate(Score ~ Group, data = dat, FUN = max) 

y el paso de merge() es simplemente

 merge(maxs, dat) 

Esto nos da el resultado deseado:

 R> maxs <- aggregate(Score ~ Group, data = dat, FUN = max) R> merge(maxs, dat) Group Score Info 1 1 3 c 2 2 4 d 

Podría, por supuesto, incluir esto en una sola línea (el paso intermedio fue más para la exposición):

 merge(aggregate(Score ~ Group, data = dat, FUN = max), dat) 

La razón principal por la que utilicé la interfaz de fórmula es que devuelve un dataframe con los names correctos para el paso de fusión; estos son los nombres de las columnas del dat conjunto de datos original. Necesitamos que el resultado de aggregate() tenga los nombres correctos para que merge() sepa qué columnas coinciden en los marcos de datos originales y agregados.

La interfaz estándar le da nombres extraños, como quiera que lo llame:

 R> aggregate(dat$Score, list(dat$Group), max) Group.1 x 1 1 3 2 2 4 R> with(dat, aggregate(Score, list(Group), max)) Group.1 x 1 1 3 2 2 4 

Podemos usar merge() en esas salidas, pero tenemos que trabajar más diciéndole a R qué columnas coinciden.

Aquí hay una solución usando el paquete plyr .

La siguiente línea de código básicamente le dice a ddply que primero ddply sus datos por grupo, y luego dentro de cada grupo devuelve un subconjunto donde la puntuación es igual a la puntuación máxima en ese grupo.

 library(plyr) ddply(data, .(Group), function(x)x[x$Score==max(x$Score), ]) Group Score Info 1 1 3 c 2 2 4 d 

Y, como señala @SachaEpskamp, ​​esto se puede simplificar aún más para:

 ddply(df, .(Group), function(x)x[which.max(x$Score), ]) 

(que también tiene la ventaja de which.max devolverá múltiples líneas máximas, si hay alguna).

El paquete plyr se puede usar para esto. Con la función ddply() puede dividir un dataframe en una o más columnas y aplicar una función y devolver un dataframe, luego con la función summarize() puede usar las columnas del dataframe dividido como variables para hacer el nuevo dataframe/;

 dat <- read.table(textConnection('Group Score Info 1 1 1 a 2 1 2 b 3 1 3 c 4 2 4 d 5 2 3 e 6 2 1 f')) library("plyr") ddply(dat,.(Group),summarize, Max = max(Score), Info = Info[which.max(Score)]) Group Max Info 1 1 3 c 2 2 4 d 

Una respuesta tardía, pero y enfoque usando data.table

 library(data.table) DT <- data.table(dat) DT[, .SD[which.max(Score),], by = Group] 

O, si es posible tener más de una puntuación igualmente alta

 DT[, .SD[which(Score == max(Score)),], by = Group] 

Observando eso (desde ?data.table

.SD es una tabla de datos que contiene el subconjunto de datos de x para cada grupo, excluyendo las columnas de grupo

Para agregar a la respuesta de Gavin: antes de la fusión, es posible hacer que aggregate use nombres propios cuando no se usa la interfaz de fórmula:

 aggregate(data[,"score", drop=F], list(group=data$group), mean) 

Así es como pienso basicamente el problema.

 my.df <- data.frame(group = rep(c(1,2), each = 3), score = runif(6), info = letters[1:6]) my.agg <- with(my.df, aggregate(score, list(group), max)) my.df.split <- with(my.df, split(x = my.df, f = group)) my.agg$info <- unlist(lapply(my.df.split, FUN = function(x) { x[which(x$score == max(x$score)), "info"] })) > my.agg Group.1 x info 1 1 0.9344336 a 2 2 0.7699763 e 

No tengo una reputación lo suficientemente alta como para comentar la respuesta de Gavin Simpson, pero quería advertir que parece haber una diferencia en el tratamiento predeterminado de los valores perdidos entre la syntax estándar y la syntax de la fórmula para aggregate .

 #Create some data with missing values a<-data.frame(day=rep(1,5),hour=c(1,2,3,3,4),val=c(1,NA,3,NA,5)) day hour val 1 1 1 1 2 1 2 NA 3 1 3 3 4 1 3 NA 5 1 4 5 #Standard syntax aggregate(a$val,by=list(day=a$day,hour=a$hour),mean,na.rm=T) day hour x 1 1 1 1 2 1 2 NaN 3 1 3 3 4 1 4 5 #Formula syntax. Note the index for hour 2 has been silently dropped. aggregate(val ~ hour + day,data=a,mean,na.rm=T) hour day val 1 1 1 1 2 3 1 3 3 4 1 5