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 chiffres 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 additionner les fréquences:
Category Frequency
First 30
Second 5
Third 34
Comment pourrais-je faire cela dans R?
Utiliser aggregate
:
aggregate(x$Frequency, by=list(Category=x$Category), FUN=sum)
Category x
1 First 30
2 Second 5
3 Third 34
Dans l'exemple ci-dessus, plusieurs dimensions peuvent être spécifiées dans list
. Plusieurs métriques agrégées du même type de données peuvent être incorporées via cbind
:
aggregate(cbind(x$Frequency, x$Metric2, x$Metric3) ...
(incorporant le commentaire @thelatemail), aggregate
possède également une interface de formule
aggregate(Frequency ~ Category, x, sum)
Ou si vous souhaitez agréger plusieurs colonnes, vous pouvez utiliser la notation .
(fonctionne également 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 de résumé (fonctionne également avec une colonne):
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 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 %>%
, reportez-vous à la section introduction à dplyr .
La réponse fournie par rcs fonctionne et est simple. Toutefois, si vous gérez 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 ce qui précède:
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 conserver la colonne, voici 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 perceptible avec des jeux de données plus volumineux, 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 plusieurs agrégations, 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 un peu lié à cette question .
Vous pouvez aussi simplement utiliser le par() une fonction:
x2 <- by(x$Frequency, x$Category, sum)
do.call(rbind,as.list(x2))
Ces autres paquets (plyr, reshape) ont l'avantage de renvoyer un nom de données.fr, mais il est intéressant de se familiariser 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'ajouter une autre solution de base R simple qui n'est pas présente ici pour une raison quelconque _ xtabs
xtabs(Frequency ~ Category, df)
# Category
# First Second Third
# 30 5 34
Ou si vous voulez un data.frame
back
as.data.frame(xtabs(Frequency ~ Category, df))
# Category Freq
# 1 First 30
# 2 Second 5
# 3 Third 34
Si x
est une base de données contenant vos données, les opérations suivantes feront ce que vous voulez:
require(reshape)
recast(x, Category ~ ., fun.aggregate=sum)
Juste pour ajouter 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 summarise
à partir de dplyr
, comme dans la réponse @docendo.
Bien que je sois récemment converti en dplyr
pour la plupart de ces types d’opérations, le paquet sqldf
est toujours vraiment agréable (et à mon humble avis, plus lisible).
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
Je trouve ave
très utile (et efficace) lorsque vous devez appliquer différentes fonctions d'agrégation sur différentes colonnes (et que vous devez/souhaitez vous en tenir à la base R):
par exemple.
Compte tenu de cette entrée:
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
nous voulons grouper par Categ1
et Categ2
et calculer la somme de Samples
et la moyenne de Freq
.
Voici une solution possible en utilisant 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),]
Résultat :
> 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
La dplyr::tally()
récemment ajoutée rend cela plus facile que jamais:
tally(x, Category)
Category n
First 30
Second 5
Third 34
Vous pouvez utiliser la fonction group.sum
de package 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 possède de nombreuses fonctions de groupe et group.sum
en fait partie.
en 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)
obtenir:
Category (all)
First 30
Second 5
Third 34