Contare il numero di righe all'interno di ogni gruppo


121

Ho un dataframe e vorrei contare il numero di righe all'interno di ogni gruppo. Uso regolarmente la aggregatefunzione per sommare i dati come segue:

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

Ora, vorrei contare le osservazioni ma non riesco a trovare l'argomento appropriato per FUN. Intuitivamente, ho pensato che sarebbe stato il seguente:

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

Ma nessuna tale fortuna.

Qualche idea?


Alcuni dati sui giocattoli:

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))

17
nrow, NROW, length...
Joshua Ulrich

15
Continuo a leggere questa domanda come se chiedessi un modo divertente per contare le cose (al contrario dei molti modi non divertenti, immagino).
Hong Ooi

6
@JoshuaUlrich: nrownon ha funzionato per me, ma NROWe lengthbene ha lavorato. +1
Prolix

Risposte:


69

La migliore pratica corrente (tidyverse) è:

require(dplyr)
df1 %>% count(Year, Month)

C'è un modo per aggregare una variabile e fare anche il conteggio (come 2 funzioni in aggregazione: mean + count)? Devo ottenere la media di una colonna e il numero di righe per lo stesso valore in un'altra colonna
sop

1
Avrei cbindi risultati di aggregate(Sepal.Length ~ Species, iris, mean)eaggregate(Sepal.Length ~ Species, iris, length)
geoteoria

L'ho fatto, ma sembra che ottengo 2 volte ogni colonna tranne quella che è aggregata; quindi ho fatto una fusione su di loro e sembra essere ok
sop

6
Non lo so ma anche questo potrebbe essere utile ...df %>% group_by(group, variable) %>% mutate(count = n())
Manoj Kumar

1
Sì, dplyr è la migliore pratica ora.
geoteoria

67

Seguendo il suggerimento di @ Joshua, ecco un modo per contare il numero di osservazioni nel tuo dfdataframe dove Year= 2007 e Month= Nov (supponendo che siano colonne):

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

e con aggregate, seguendo @GregSnow:

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

47

dplyrpackage lo fa con count/ tallycommands, o la n()funzione :

Innanzitutto, alcuni dati:

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

Ora il conteggio:

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

Possiamo anche utilizzare una versione leggermente più lunga con piping e la n()funzione:

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

o la tallyfunzione:

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

37

Una vecchia domanda senza data.tablesoluzione. Quindi ecco qua ...

utilizzando .N

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

1
standard al giorno d'oggi da utilizzare al .()posto di list()e setDT()per convertire un data.frame in data.table. Quindi in un solo passaggio setDT(df)[, .N, by = .(year, month)].
sindri_baldur

23

La semplice opzione da utilizzare aggregateè la lengthfunzione che ti darà la lunghezza del vettore nel sottoinsieme. A volte è un po 'più robusto da usare function(x) sum( !is.na(x) ).


18

Crea una nuova variabile Countcon un valore di 1 per ogni riga:

df1["Count"] <-1

Quindi aggrega il dataframe, sommando per Count colonna:

df2 <- aggregate(df1[c("Count")], by=list(Year=df1$Year, Month=df1$Month), FUN=sum, na.rm=TRUE)

Solo per notare che se stai usando il metodo predefinito, senza formula per aggregate, non c'è bisogno di rinominare ogni variabile by=come list(year=df1$year)ecc. A data.frameè listgià così aggregate(df1[c("Count")], by=df1[c("Year", "Month")], FUN=sum, na.rm=TRUE)funzionerà.
recapito del

17

Un'alternativa alla aggregate()funzione in questo caso sarebbe table()con as.data.frame(), che indicherebbe anche quali combinazioni di Anno e Mese sono associate a zero occorrenze

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")]))

E senza le combinazioni che si verificano zero

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

7

Se vuoi includere 0 conteggi per mesi-anni mancanti nei dati, puoi usare un po 'di tablemagia.

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

Ad esempio, il toy data.frame nella domanda, df1, non contiene osservazioni di gennaio 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 aggregatefunzione di base R non restituisce un'osservazione per gennaio 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

Se desideri un'osservazione di questo mese-anno con 0 come conteggio, il codice sopra restituirà un data.frame con i conteggi per tutte le combinazioni mese-anno:

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

5

Per le mie aggregazioni di solito finisco per voler vedere la media e "quanto è grande questo gruppo" (aka lunghezza). Quindi questo è il mio utile frammento per quelle occasioni;

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

UN soluzione utilizzando il sqldfpacchetto:

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

1

Considerando la risposta di @Ben, R genererebbe un errore se df1non contiene xcolonne. Ma può essere risolto elegantemente con paste:

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

Allo stesso modo, può essere generalizzato se nel raggruppamento vengono utilizzate più di due variabili:

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

0

È possibile utilizzare byfunzioni poiché by(df1$Year, df1$Month, count)ciò produrrà un elenco di aggregazioni necessarie.

L'output sarà simile a

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

Ci sono già molte meravigliose risposte qui, ma volevo aggiungere un'altra opzione per coloro che desiderano aggiungere una nuova colonna al set di dati originale che contiene il numero di volte in cui quella riga viene ripetuta.

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

Lo stesso potrebbe essere ottenuto combinando una qualsiasi delle risposte precedenti con la merge()funzione.


0

Se stai provando le soluzioni aggregate sopra e ottieni l'errore:

tipo non valido (elenco) per la variabile

Poiché stai utilizzando i timbri data o datetime, prova a utilizzare as.character sulle variabili:

aggregate(x ~ as.character(Year) + Month, data = df, FUN = length)

Su una o entrambe le variabili.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.