Cómo sumr una variable por grupo?

Digamos que tengo dos columnas de datos. El primero contiene categorías como “Primero”, “Segundo”, “Tercero”, etc. El segundo tiene números que representan la cantidad de veces que vi “Primero”.

Por ejemplo:

Category Frequency First 10 First 15 First 5 Second 2 Third 14 Third 20 Second 3 

Quiero ordenar los datos por categoría y sumr las frecuencias:

 Category Frequency First 30 Second 5 Third 34 

¿Cómo haría esto en R?

Usando aggregate :

 aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum) Category x 1 First 30 2 Second 5 3 Third 34 

(incorporando @thelatemail comment), aggregate tiene una interfaz de fórmula

 aggregate(Frequency ~ Category, x, sum) 

O si desea agregar columnas múltiples, puede usar . notación (también funciona para una columna)

 aggregate(. ~ Category, x, sum) 

o tapply :

 tapply(x$Frequency, x$Category, FUN=sum) First Second Third 30 5 34 

Usando esta información:

 x <- data.frame(Category=factor(c("First", "First", "First", "Second", "Third", "Third", "Second")), Frequency=c(10,15,5,2,14,20,3)) 

Más recientemente, también puede usar el paquete dplyr para ese propósito:

 library(dplyr) x %>% group_by(Category) %>% summarise(Frequency = sum(Frequency)) #Source: local data frame [3 x 2] # # Category Frequency #1 First 30 #2 Second 5 #3 Third 34 

O bien, para varias columnas de resumen (también funciona con una columna):

 x %>% group_by(Category) %>% summarise_each(funs(sum)) 

Actualización para dplyr> = 0.5: summarise_each ha sido reemplazado por summarise_all , summarise_at y summarise_if familia de funciones en dplyr.

O bien, si tiene varias columnas para agrupar, puede especificarlas todas en el group_by separado con comas:

 mtcars %>% group_by(cyl, gear) %>% # multiple group columns summarise(max_hp = max(hp), mean_mpg = mean(mpg)) # multiple summary columns 

Para obtener más información, incluido el operador %>% , consulte la introducción a dplyr .

La respuesta proporcionada por rcs funciona y es simple. Sin embargo, si está manejando conjuntos de datos más grandes y necesita un aumento de rendimiento, existe una alternativa más rápida:

 library(data.table) data = data.table(Category=c("First","First","First","Second","Third", "Third", "Second"), Frequency=c(10,15,5,2,14,20,3)) data[, sum(Frequency), by = Category] # Category V1 # 1: First 30 # 2: Second 5 # 3: Third 34 system.time(data[, sum(Frequency), by = Category] ) # user system elapsed # 0.008 0.001 0.009 

Comparemos eso con lo mismo usando data.frame y lo anterior:

 data = data.frame(Category=c("First","First","First","Second","Third", "Third", "Second"), Frequency=c(10,15,5,2,14,20,3)) system.time(aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum)) # user system elapsed # 0.008 0.000 0.015 

Y si desea conservar la columna, esta es la syntax:

 data[,list(Frequency=sum(Frequency)),by=Category] # Category Frequency # 1: First 30 # 2: Second 5 # 3: Third 34 

La diferencia será más notable con conjuntos de datos más grandes, como lo demuestra el siguiente código:

 data = data.table(Category=rep(c("First", "Second", "Third"), 100000), Frequency=rnorm(100000)) system.time( data[,sum(Frequency),by=Category] ) # user system elapsed # 0.055 0.004 0.059 data = data.frame(Category=rep(c("First", "Second", "Third"), 100000), Frequency=rnorm(100000)) system.time( aggregate(data$Frequency, by=list(Category=data$Category), FUN=sum) ) # user system elapsed # 0.287 0.010 0.296 

Para agregaciones múltiples, puede combinar lapply y .SD siguiente manera

 data[, lapply(.SD, sum), by = Category] # Category Frequency # 1: First 30 # 2: Second 5 # 3: Third 34 

Esto está relacionado de alguna manera con esta pregunta .

También puede usar la función by () :

 x2 <- by(x$Frequency, x$Category, sum) do.call(rbind,as.list(x2)) 

Esos otros paquetes (plyr, remodelar) tienen el beneficio de devolver un data.frame, pero vale la pena familiarizarse con () ya que es una función base.

 library(plyr) ddply(tbl, .(Category), summarise, sum = sum(Frequency)) 

Varios años más tarde, solo para agregar otra solución simple de base R que no está presente aquí por alguna razón: xtabs

 xtabs(Frequency ~ Category, df) # Category # First Second Third # 30 5 34 

O si quieres un data.frame nuevo

 as.data.frame(xtabs(Frequency ~ Category, df)) # Category Freq # 1 First 30 # 2 Second 5 # 3 Third 34 

Solo para agregar una tercera opción:

 require(doBy) summaryBy(Frequency~Category, data=yourdataframe, FUN=sum) 

EDITAR: esta es una respuesta muy antigua. Ahora recomendaría el uso de group_by y resumir desde dplyr, como en @docendo answer.

Si bien recientemente me he convertido en un converso a dplyr para la mayoría de estos tipos de operaciones, el paquete sqldf sigue siendo realmente agradable (y en mi humilde opinión más legible) para algunas cosas.

Aquí hay un ejemplo de cómo se puede responder esta pregunta con sqldf

 x <- data.frame(Category=factor(c("First", "First", "First", "Second", "Third", "Third", "Second")), Frequency=c(10,15,5,2,14,20,3)) sqldf("select Category ,sum(Frequency) as Frequency from x group by Category") ## Category Frequency ## 1 First 30 ## 2 Second 5 ## 3 Third 34 

Si x es un dataframe con sus datos, lo siguiente hará lo que desee:

 require(reshape) recast(x, Category ~ ., fun.aggregate=sum) 

usando cast lugar de recast (nota 'Frequency' ahora es 'value' )

 df <- data.frame(Category = c("First","First","First","Second","Third","Third","Second") , value = c(10,15,5,2,14,20,3)) install.packages("reshape") result<-cast(df, Category ~ . ,fun.aggregate=sum) 

Llegar:

 Category (all) First 30 Second 5 Third 34