Pregunta

Vamos a decir que tengo dos columnas de datos. El primero contiene categorías tales como "primero", "segundo", "tercero", etc. La segunda tiene números que representan el número de veces que la 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 sumar las frecuencias:

Category     Frequency
First        30
Second       5
Third        34

¿Cómo voy a hacer esto en R?

¿Fue útil?

Solución

El uso de aggregate:

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

En el ejemplo anterior, dimensiones múltiples se pueden especificar en el list. Múltiples métricas agregadas del mismo tipo de datos pueden ser incorporados a través de cbind:

aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...

(incrustación comentario @thelatemail), aggregate tiene una interfaz de fórmula demasiado

aggregate(Frequency ~ Category, x, sum)

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

aggregate(. ~ Category, x, sum)

o tapply:

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

El uso de estos datos:

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

Otros consejos

Más recientemente, también se puede utilizar el dplyr paquete 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, para las columnas Resumen múltiple (trabaja con una columna también):

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 familiares summarise_if de funciones en dplyr

O, si usted tiene varias columnas para agrupar por, puede especificar todos ellos en el group_by separados por 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, incluyendo el operador %>%, ver la introducción rel="noreferrer"> href="https://cran.r-project.org/web/packages/dplyr/vignettes/dplyr.html" .

La respuesta proporcionada por RCS funciona y es simple. Sin embargo, si usted está manejando grandes conjuntos de datos y la necesidad de un aumento de rendimiento no es 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 

Vamos a comparar eso a lo mismo usando hoja.de.datos y por encima de todo 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 mantener la columna esta es la sintaxis:

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 grandes conjuntos de datos, como el código siguiente muestra:

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 múltiples agregaciones, se pueden combinar lapply y .SD de la siguiente manera

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

Esto es algo relacionado con esta pregunta.

Puede también usar simplemente () función:

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

Los otros paquetes (plyr, remodelar) tienen la ventaja de devolver un hoja.de.datos, pero vale la pena estar familiarizado con por (), ya que es una función de base.

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

Varios años más tarde, sólo para añadir otra solución base de R sencilla que no está presente aquí por algún xtabs razonable

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

O si quieres un data.frame volver

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

Si x es una trama de datos con sus datos, entonces lo siguiente hace lo que quiere:

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

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

A continuación se muestra un ejemplo de cómo esta pregunta puede responderse 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

Sólo para añadir una tercera opción:

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

EDIT: se trata de una respuesta muy antigua. Ahora me gustaría recomendar el uso de group_by y summarise de dplyr, como en @docendo respuesta.

El dplyr::tally() recientemente añadido ahora hace que esto sea más fácil que nunca:

tally(x, Category)

Category     n
First        30
Second       5
Third        34

ave muy útil (y eficiente) cuando es necesario aplicar diferentes funciones de agregación en diferentes columnas (y debe / quiere meter en la base R):

por ejemplo.

Dada esta entrada:

DF <-                
data.frame(Categ1=factor(c('A','A','B','B','A','B','A')),
           Categ2=factor(c('X','Y','X','X','X','Y','Y')),
           Samples=c(1,2,4,3,5,6,7),
           Freq=c(10,30,45,55,80,65,50))

> DF
  Categ1 Categ2 Samples Freq
1      A      X       1   10
2      A      Y       2   30
3      B      X       4   45
4      B      X       3   55
5      A      X       5   80
6      B      Y       6   65
7      A      Y       7   50

queremos agrupar por Categ1 y Categ2 y calcular la suma de Samples y media de Freq.
Aquí hay una solución posible usando ave:

# create a copy of DF (only the grouping columns)
DF2 <- DF[,c('Categ1','Categ2')]

# add sum of Samples by Categ1,Categ2 to DF2 
# (ave repeats the sum of the group for each row in the same group)
DF2$GroupTotSamples <- ave(DF$Samples,DF2,FUN=sum)

# add mean of Freq by Categ1,Categ2 to DF2 
# (ave repeats the mean of the group for each row in the same group)
DF2$GroupAvgFreq <- ave(DF$Freq,DF2,FUN=mean)

# remove the duplicates (keep only one row for each group)
DF2 <- DF2[!duplicated(DF2),]

Resultados:

> DF2
  Categ1 Categ2 GroupTotSamples GroupAvgFreq
1      A      X               6           45
2      A      Y               9           40
3      B      X               7           50
6      B      Y               6           65

Se puede utilizar la función de group.sum paquete Rfast .

Category <- Rfast::as_integer(Category,result.sort=FALSE) # convert character to numeric. R's as.numeric produce NAs.
result <- Rfast::group.sum(Frequency,Category)
names(result) <- Rfast::Sort(unique(Category)
# 30 5 34

Rfast tiene muchas funciones de grupo y group.sum es uno de ellos.

usando cast en lugar de recast (nota 'Frequency' es ahora '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)

para obtener:

Category (all)
First     30
Second    5
Third     34
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top