Zählen Sie die Anzahl der Zeilen innerhalb jeder Gruppe


121

Ich habe einen Datenrahmen und möchte die Anzahl der Zeilen innerhalb jeder Gruppe zählen. Ich benutze die aggregateFunktion regelmäßig, um Daten wie folgt zu summieren:

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

Jetzt möchte ich Beobachtungen zählen, kann aber anscheinend nicht das richtige Argument dafür finden FUN. Intuitiv dachte ich, es wäre wie folgt:

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

Aber kein solches Glück.

Irgendwelche Ideen?


Einige Spielzeugdaten:

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
Ich lese diese Frage immer wieder, indem ich nach einer lustigen Art frage, Dinge zu zählen (im Gegensatz zu den vielen nicht lustigen Möglichkeiten, denke ich).
Hong Ooi

6
@JoshuaUlrich: nrowhat bei mir aber nicht funktioniert NROWund hat gut lengthfunktioniert. +1
Prolix

Antworten:


69

Aktuelle Best Practice (Tidyverse) ist:

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

Gibt es eine Möglichkeit, eine Variable zu aggregieren und auch zu zählen (wie 2 Funktionen in der Aggregation: Mittelwert + Anzahl)? Ich muss den Mittelwert einer Spalte und die Anzahl der Zeilen für den gleichen Wert in einer anderen Spalte ermitteln
sop

1
Ich würde cbinddie Ergebnisse von aggregate(Sepal.Length ~ Species, iris, mean)undaggregate(Sepal.Length ~ Species, iris, length)
Geotheory

Ich habe es getan, aber es scheint, dass ich 2 Mal jede Spalte bekomme, außer der, die aggregiert ist; Also habe ich sie zusammengeführt und es scheint in Ordnung zu sein
sop

6
Ich weiß nicht, aber das könnte auch nützlich sein ...df %>% group_by(group, variable) %>% mutate(count = n())
Manoj Kumar

1
Ja, dplyr ist jetzt die beste Vorgehensweise.
Geotheory

67

Nach dem Vorschlag von @ Joshua können Sie auf folgende Weise die Anzahl der Beobachtungen in Ihrem dfDatenrahmen zählen, wobei Year= 2007 und Month= Nov (vorausgesetzt, es handelt sich um Spalten):

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

und mit aggregatefolgendem @GregSnow:

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

47

dplyrPaket macht dies mit count/ tallyBefehlen oder der n()Funktion :

Zunächst einige Daten:

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

Nun die Zählung:

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

Wir können auch eine etwas längere Version mit Rohrleitungen und der n()Funktion verwenden:

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

oder die tallyFunktion:

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

37

Eine alte Frage ohne data.tableLösung. Also los geht's ...

Verwenden von .N

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

1
Heutzutage ist es Standard , einen data.frame .()anstelle von data.table zu verwenden list()und setDT()zu konvertieren. Also in einem Schritt setDT(df)[, .N, by = .(year, month)].
Sindri_baldur

23

Die einfache Option aggregateist die lengthFunktion, mit der Sie die Länge des Vektors in der Teilmenge angeben können. Manchmal ist es etwas robuster zu bedienen function(x) sum( !is.na(x) ).


18

Erstellen Sie Countfür jede Zeile eine neue Variable mit dem Wert 1:

df1["Count"] <-1

Aggregieren Sie dann den Datenrahmen und summieren Sie ihn nach der CountSpalte:

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

Nur um zu beachten, dass, wenn Sie die Standardmethode ohne Formel für verwenden aggregate, es nicht erforderlich ist, jede Variable in " by=Gefällt mir" list(year=df1$year)usw. umzubenennen . A data.frameist eine listbereits so aggregate(df1[c("Count")], by=df1[c("Year", "Month")], FUN=sum, na.rm=TRUE)wird funktionieren.
E-Mail

17

Eine Alternative zu der aggregate()Funktion in diesem Fall wäre table()mit as.data.frame(), die auch angibt, welche Kombinationen von Jahr und Monat mit null Vorkommen verbunden sind

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

Und ohne die null auftretenden Kombinationen

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

7

Wenn Sie 0 Zählungen für Monatsjahre einschließen möchten, die in den Daten fehlen, können Sie ein wenig tableMagie verwenden.

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

Beispielsweise enthält der Spielzeugdatenrahmen in der Frage df1 keine Beobachtungen vom Januar 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

Die Basis-R- aggregateFunktion gibt keine Beobachtung für Januar 2014 zurück.

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

Wenn Sie eine Beobachtung dieses Monatsjahres mit 0 als Zählung wünschen, gibt der obige Code einen data.frame mit Zählungen für alle Monat-Jahr-Kombinationen zurück:

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

Für meine Aggregationen möchte ich normalerweise den Mittelwert und "wie groß ist diese Gruppe" (auch bekannt als Länge) sehen. Das ist also mein praktischer Ausschnitt für diese Gelegenheiten;

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

EIN Lösung mit sqldfPaket:

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

1

In Anbetracht der @ Ben-Antwort würde R einen Fehler auslösen, wenn df1keine xSpalte enthalten ist . Aber es kann elegant gelöst werden mit paste:

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

Ebenso kann verallgemeinert werden, wenn bei der Gruppierung mehr als zwei Variablen verwendet werden:

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

0

Sie können byFunktionen verwenden by(df1$Year, df1$Month, count), um eine Liste der erforderlichen Aggregationen zu erstellen.

Die Ausgabe sieht aus wie folgt:

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

Es gibt hier bereits viele wundervolle Antworten, aber ich wollte eine weitere Option für diejenigen einfügen, die dem ursprünglichen Datensatz eine neue Spalte hinzufügen möchten, die die Häufigkeit enthält, mit der diese Zeile wiederholt wird.

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

Das gleiche könnte erreicht werden, indem eine der obigen Antworten mit der merge()Funktion kombiniert wird .


0

Wenn Sie die oben genannten Aggregatlösungen ausprobieren und die folgende Fehlermeldung erhalten:

ungültiger Typ (Liste) für Variable

Versuchen Sie, as.character für die Variablen zu verwenden, da Sie Datums- oder Datums- / Uhrzeitstempel verwenden:

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

Auf eine oder beide Variablen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.