web-dev-qa-db-fra.com

Compter le nombre de lignes dans chaque groupe

J'ai une base de données et j'aimerais compter le nombre de lignes dans chaque groupe. J'utilise régulièrement la fonction aggregate pour additionner les données comme suit:

df2 <- aggregate(x ~ Year + Month, data = df1, sum)

Maintenant, j'aimerais compter les observations, mais n'arrive pas à trouver le bon argument pour FUN. Intuitivement, j'ai pensé que ce serait comme suit:

df2 <- aggregate(x ~ Year + Month, data = df1, count)

Mais pas de chance.

Des idées?


Quelques données sur les jouets:

set.seed(2)
df1 <- data.frame(x = 1:20,
                  Year = sample(2012:2014, 20, replace = TRUE),
                  Month = sample(month.abb[1:3], 20, replace = TRUE))
85
MikeTP

Il y a aussi df2 <- count(x, c('Year','Month')) (paquet plyr)

45
geotheory

En suivant la suggestion de @ Joshua, voici une façon de compter le nombre d'observations dans votre cadre de données dfYear = 2007 et Month = Nov (en supposant qu'il s'agisse de colonnes):

nrow(df[,df$YEAR == 2007 & df$Month == "Nov"])

et avec aggregate, à la suite de @GregSnow:

aggregate(x ~ Year + Month, data = df, FUN = length)
52
Ben

Nous pouvons également utiliser dplyr.

Tout d'abord, quelques données:

df <- data.frame(x = rep(1:6, rep(c(1, 2, 3), 2)), year = 1993:2004, month = c(1, 1:11))

Maintenant le compte:

library(dplyr)
count(df, year, month)
#piping
df %>% count(year, month)

Nous pouvons également utiliser une version légèrement plus longue avec tuyauterie et fonction n():

df %>% 
  group_by(year, month) %>%
  summarise(number = n())

ou la fonction tally:

df %>% 
  group_by(year, month) %>%
  tally()
32
jeremycg

Une vieille question sans solution data.table. Alors voilà ...

Utiliser .N 

library(data.table)
DT <- data.table(df)
DT[, .N, by = list(year, month)]
30
mnel

L'option simple à utiliser avec aggregate est la fonction length qui vous donnera la longueur du vecteur dans le sous-ensemble. Parfois, un peu plus robuste consiste à utiliser function(x) sum( !is.na(x) ).

21
Greg Snow

Créez une nouvelle variable Count avec une valeur de 1 pour chaque ligne:

df1["Count"] <-1

Puis agrégez la base de données en faisant la somme de la colonne Count:

df2 <- aggregate(df1[c("Count")], by=list(year=df1$year, month=df1$month), FUN=sum, na.rm=TRUE)
16
Leroy Tyrone

Une alternative à la fonction aggregate() dans ce cas serait table() avec as.data.frame(), qui indiquerait également quelles combinaisons d'année et de mois sont associées à zéro

df<-data.frame(x=rep(1:6,rep(c(1,2,3),2)),year=1993:2004,month=c(1,1:11))

myAns<-as.data.frame(table(df[,c("year","month")]))

Et sans les combinaisons nulles

myAns[which(myAns$Freq>0),]
15
BenBarnes

Si vous souhaitez inclure 0 nombre pour les mois-années manquants dans les données, vous pouvez utiliser un peu de magie table.

data.frame(with(df1, table(Year, Month)))

Par exemple, le jouet data.frame dans la question, df1, ne contient aucune observation de janvier 2014.

df1
    x Year Month
1   1 2012   Feb
2   2 2014   Feb
3   3 2013   Mar
4   4 2012   Jan
5   5 2014   Feb
6   6 2014   Feb
7   7 2012   Jan
8   8 2014   Feb
9   9 2013   Mar
10 10 2013   Jan
11 11 2013   Jan
12 12 2012   Jan
13 13 2014   Mar
14 14 2012   Mar
15 15 2013   Feb
16 16 2014   Feb
17 17 2014   Mar
18 18 2012   Jan
19 19 2013   Mar
20 20 2012   Jan

La fonction de base R aggregate ne renvoie pas d'observation pour janvier 2014.

aggregate(x ~ Year + Month, data = df1, FUN = length)
  Year Month x
1 2012   Feb 1
2 2013   Feb 1
3 2014   Feb 5
4 2012   Jan 5
5 2013   Jan 2
6 2012   Mar 1
7 2013   Mar 3
8 2014   Mar 2

Si vous souhaitez une observation de cette année mois avec 0 comme nombre, le code ci-dessus renvoie un nom data.frame avec des comptes pour toutes les combinaisons mois-année:

data.frame(with(df1, table(Year, Month)))
  Year Month Freq
1 2012   Feb    1
2 2013   Feb    1
3 2014   Feb    5
4 2012   Jan    5
5 2013   Jan    2
6 2014   Jan    0
7 2012   Mar    1
8 2013   Mar    3
9 2014   Mar    2
7
lmo

Pour mes agrégations, je finis généralement par vouloir voir la moyenne et "quelle est la taille de ce groupe" (longueur.k.a.) ... C'est donc mon extrait pratique pour ces occasions;

agg.mean <- aggregate(columnToMean ~ columnToAggregateOn1*columnToAggregateOn2, yourDataFrame, FUN="mean")
agg.count <- aggregate(columnToMean ~ columnToAggregateOn1*columnToAggregateOn2, yourDataFrame, FUN="length")
aggcount <- agg.count$columnToMean
agg <- cbind(aggcount, agg.mean)
4
maze

Une solution sql utilisant le package sqldf:

library(sqldf)
sqldf("SELECT Year, Month, COUNT(*) as Freq
       FROM df1
       GROUP BY Year, Month")
2
M-M

En considérant @Ben answer, R émettrait une erreur si df1 ne contient pas de colonne x. Mais cela peut être résolu élégamment avec paste:

aggregate(paste(Year, Month) ~ Year + Month, data = df1, FUN = NROW)

De même, il peut être généralisé si plus de deux variables sont utilisées dans le regroupement:

aggregate(paste(Year, Month, Day) ~ Year + Month + Day, data = df1, FUN = NROW)
0
paudan

Il y a déjà beaucoup de réponses merveilleuses ici, mais je voulais ajouter une option supplémentaire à ceux qui souhaitent ajouter une nouvelle colonne au jeu de données d'origine contenant le nombre de répétitions de cette ligne.

df1$counts <- sapply(X = paste(df1$Year, df1$Month), 
                     FUN = function(x) { sum(paste(df1$Year, df1$Month) == x) })

La même chose pourrait être accomplie en combinant l’une des réponses ci-dessus avec la fonction merge().

0
filups21

Vous pouvez utiliser les fonctions by en tant que by(df1$Year, df1$Month, count) qui produira une liste des agrégations nécessaires.

La sortie ressemblera à 

df1$Month: Feb
     x freq
1 2012    1
2 2013    1
3 2014    5
--------------------------------------------------------------- 
df1$Month: Jan
     x freq
1 2012    5
2 2013    2
--------------------------------------------------------------- 
df1$Month: Mar
     x freq
1 2012    1
2 2013    3
3 2014    2
> 
0
helcode