Comment additionner une variable par groupe?

Disons que j’ai deux colonnes de données. Le premier contient des catégories telles que “Premier”, “Deuxième”, “Troisième”, etc. Le second contient des nombres qui représentent le nombre de fois où j’ai vu “Premier”.

Par exemple:

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

Je veux sortinger les données par catégorie et additionner les fréquences:

 Category Frequency First 30 Second 5 Third 34 

Comment pourrais-je le faire en R?

En utilisant l’ aggregate :

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

(incorporation du commentaire @thelatemail), l’ aggregate a aussi une interface de formule

 aggregate(Frequency ~ Category, x, sum) 

Ou si vous souhaitez agréger plusieurs colonnes, vous pouvez utiliser le . notation (fonctionne aussi pour une colonne)

 aggregate(. ~ Category, x, sum) 

ou tapply :

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

En utilisant ces données:

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

Plus récemment, vous pouvez également utiliser le package dplyr à cette fin:

 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 

Ou, pour plusieurs colonnes récapitulatives (fonctionne également avec une colonne):

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

Mise à jour pour dplyr> = 0.5: la fonction summarise_each a été remplacée par la famille de fonctions summary_all, summary, summarise_at et summarise_if dans dplyr.

Ou, si vous avez plusieurs colonnes à regrouper, vous pouvez toutes les spécifier dans le group_by séparé par des virgules:

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

Pour plus d’informations, y compris l’opérateur %>% , voir l’ introduction à dplyr .

La réponse fournie par rcs fonctionne et est simple. Cependant, si vous manipulez des ensembles de données plus volumineux et que vous avez besoin d’une amélioration des performances, il existe une alternative plus rapide:

 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 

Comparons cela à la même chose en utilisant data.frame et ci-dessus:

 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 

Et si vous voulez garder la colonne c’est la syntaxe:

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

La différence deviendra plus évidente avec des ensembles de données plus importants, comme le montre le code ci-dessous:

 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 

Pour les agrégations multiples, vous pouvez combiner lapply et .SD comme suit

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

Ceci est quelque peu lié à cette question .

Vous pouvez aussi simplement utiliser la fonction by () :

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

Ces autres paquets (plyr, reshape) ont l'avantage de retourner un data.frame, mais cela vaut la peine d'être connu avec by () car c'est une fonction de base.

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

Plusieurs années plus tard, il suffit d’append une autre solution simple de base R qui n’est pas présente ici pour certains xtabs

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

Ou si vous voulez un data.frame

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

Juste pour append une troisième option:

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

EDIT: c’est une très vieille réponse. Maintenant, je recommanderais l’utilisation de group_by et résumer à partir de dplyr, comme dans @docendo répond.

Bien que je sois récemment devenu un converti en dplyr pour la plupart de ces types d’opérations, le paquetage sqldf est toujours très sympa (et IMHO plus lisible) pour certaines choses.

Voici un exemple de réponse à cette question avec 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 est un dataframe avec vos données, alors ce qui suit fera ce que vous voulez:

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

utiliser cast au lieu de recast (note 'Frequency' est maintenant '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) 

obtenir:

 Category (all) First 30 Second 5 Third 34