Comment additionner une variable par groupe?
disons que j'ai deux colonnes de données. La première contient les catégories telles que "Première", "Deuxième", "Troisième", etc. Le second a 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 trier les données par catégorie et faire la somme des fréquences:
Category Frequency
First 30
Second 5
Third 34
comment je ferais ça en R?
10 réponses
utilisant aggregate
:
aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
Category x
1 First 30
2 Second 5
3 Third 34
(embedding @thelatemail comment), aggregate
a une interface de formule trop
aggregate(Frequency ~ Category, x, sum)
ou si vous voulez agréger plusieurs colonnes, vous pouvez utiliser la notation .
(fonctionne pour une colonne aussi)
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 la fonction dplyr package à cet effet:
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 les plusieurs colonnes de synthèse (fonctionne avec une colonne trop):
x %>%
group_by(Category) %>%
summarise_each(funs(sum))
mise à jour pour dplyr >= 0.5: summarise_each
a été remplacé par summarise_all
, summarise_at
et summarise_if
famille de fonctions en dplyr.
Ou, si vous avez plusieurs colonnes pour grouper par, vous pouvez tous 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'information, y compris l'opérateur %>%
, voir la introduction à dplyr .
La réponse fournie par rcs fonctionne et est simple. Cependant, si vous manipulez des ensembles de données plus grands et avez besoin d'une augmentation de la performance, Il ya 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 des données.image 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 sera de plus en plus perceptible avec les ensembles de données plus le code ci-dessous démontre:
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
c'est quelque peu lié à cette question .
vous pouvez également utiliser le par () fonction:
x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))
ces autres paquets (plyr, reshape) ont l'avantage de renvoyer une donnée.frame, mais cela vaut la peine d'être familier avec by() car c'est une fonction de base.
library(plyr)
ddply(tbl, .(Category), summarise, sum = sum(Frequency))
plusieurs années plus tard, juste pour ajouter une autre solution de base simple R qui n'est pas présent ici pour une raison quelconque - xtabs
xtabs(Frequency ~ Category, df)
# Category
# First Second Third
# 30 5 34
ou si vous voulez un data.frame
arrière
as.data.frame(xtabs(Frequency ~ Category, df))
# Category Freq
# 1 First 30
# 2 Second 5
# 3 Third 34
juste pour ajouter une troisième option:
require(doBy)
summaryBy(Frequency~Category, data=yourdataframe, FUN=sum)
EDIT: c'est une réponse très ancienne. Maintenant, je recommande l'utilisation de group_by et de résumer de dplyr, comme dans la réponse de @docendo.
alors que je suis récemment devenu un converti en dplyr
pour la plupart de ces types d'opérations, le paquet sqldf
est encore vraiment agréable (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 une dataframe avec vos données, alors ce qui suit fera ce que vous voulez:
require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
utilisant 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)
pour obtenir:
Category (all)
First 30
Second 5
Third 34