Policz liczbę wierszy w każdej grupie


121

Mam ramkę danych i chciałbym policzyć wiersze w każdej grupie. Regularnie używam aggregatefunkcji do sumowania danych w następujący sposób:

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

Chciałbym teraz policzyć obserwacje, ale nie mogę znaleźć odpowiedniego argumentu za FUN. Intuicyjnie pomyślałem, że będzie tak:

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

Ale nie ma takiego szczęścia.

Jakieś pomysły?


Niektóre dane dotyczące zabawek:

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
Wciąż czytam to pytanie jako prośbę o fajny sposób liczenia rzeczy (w przeciwieństwie do wielu nienajlepszych sposobów, jak sądzę).
Hong Ooi

6
@JoshuaUlrich: nrownie działa dla mnie, ale NROWi lengthdziała dobrze. +1
Prolix

Odpowiedzi:


69

Aktualna najlepsza praktyka (tidyverse) to:

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

Czy istnieje sposób na agregowanie zmiennej i zliczanie również (np. 2 funkcje w agregacji: średnia + liczba)? Muszę uzyskać średnią z kolumny i liczbę wierszy dla tej samej wartości w innej kolumnie
sop

1
Miałem cbindwyniki aggregate(Sepal.Length ~ Species, iris, mean)iaggregate(Sepal.Length ~ Species, iris, length)
geoteoria

Zrobiłem to, ale wygląda na to, że otrzymuję 2 razy w każdej kolumnie, z wyjątkiem tej, która jest zagregowana; więc dokonałem ich scalenia i wydaje się, że jest ok
sop

6
Nie wiem, ale to też mogłoby się przydać ...df %>% group_by(group, variable) %>% mutate(count = n())
Manoj Kumar,

1
Tak, dplyr jest teraz najlepszą praktyką.
geoteoria

67

Zgodnie z sugestią @ Joshua, oto jeden ze sposobów obliczenia liczby obserwacji w dframce danych, gdzie Year= 2007 i Month= Lis (zakładając, że są to kolumny):

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

i za pomocą aggregate@GregSnow:

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

47

dplyrpakiet robi to za pomocą count/ tallycommands lub n()funkcji :

Najpierw trochę danych:

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

Teraz liczyć:

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

Możemy też zastosować nieco dłuższą wersję z lamówką i n()funkcją:

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

lub tallyfunkcja:

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

37

Stare pytanie bez data.tablerozwiązania. Więc oto idzie ...

Za pomocą .N

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

1
standard w dzisiejszych czasach do użycia .()zamiast list()i setDT()do konwersji data.frame do data.table. Więc w jednym kroku setDT(df)[, .N, by = .(year, month)].
sindri_baldur

23

Prostą opcją do użycia z aggregatejest lengthfunkcja, która poda długość wektora w podzbiorze. Czasami użycie jest trochę bardziej niezawodne function(x) sum( !is.na(x) ).


18

Utwórz nową zmienną Counto wartości 1 dla każdego wiersza:

df1["Count"] <-1

Następnie zagreguj ramkę danych, sumując według Countkolumny:

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

Wystarczy zauważyć, że jeśli używasz domyślnej, nieformułowanej metody for aggregate, nie ma potrzeby zmiany nazwy każdej zmiennej w by=like list(year=df1$year)itp. A data.framejest listjuż tak, że aggregate(df1[c("Count")], by=df1[c("Year", "Month")], FUN=sum, na.rm=TRUE)będzie działać.
thelatemail

17

Alternatywą dla aggregate()funkcji w tym przypadku byłaby table()z as.data.frame(), która wskazywałaby również, które kombinacje roku i miesiąca są powiązane z zerową liczbą wystąpień

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

I bez kombinacji występujących zero

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

7

Jeśli chcesz uwzględnić 0 zliczeń dla miesięcy-lat, których brakuje w danych, możesz użyć trochę tablemagii.

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

Na przykład zabawkowa ramka data.frame w pytaniu, df1, nie zawiera żadnych obserwacji ze stycznia 2014 r.

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

Podstawowa aggregatefunkcja R nie zwraca obserwacji ze stycznia 2014 r.

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

Jeśli chcesz obserwować ten miesiąc-rok z 0 jako liczbą, powyższy kod zwróci ramkę data.frame z licznikami dla wszystkich kombinacji miesiąc-rok:

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

W przypadku moich agregacji zwykle chcę zobaczyć średnią i „jak duża jest ta grupa” (czyli długość). Więc to jest mój przydatny fragment na te okazje;

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)

5

ZA rozwiązanie za pomocą sqldfpakietu:

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

1

Biorąc pod uwagę odpowiedź @Ben, R wyrzuci błąd, jeśli df1nie zawiera xkolumny. Ale można to elegancko rozwiązać za pomocą paste:

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

Podobnie można uogólnić, jeśli w grupowaniu są używane więcej niż dwie zmienne:

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

0

Możesz użyć byfunkcji, ponieważ by(df1$Year, df1$Month, count)utworzą one listę potrzebnych agregacji.

Wynik będzie wyglądał następująco:

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

Jest tu już wiele wspaniałych odpowiedzi, ale chciałem dodać jeszcze 1 opcję dla tych, którzy chcą dodać nową kolumnę do oryginalnego zbioru danych, która zawiera liczbę powtórzeń tego wiersza.

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

To samo można osiągnąć, łącząc dowolną z powyższych odpowiedzi z merge()funkcją.


0

Jeśli wypróbowujesz powyższe rozwiązania zagregowane i pojawi się błąd:

nieprawidłowy typ (lista) dla zmiennej

Ponieważ używasz znaczników daty lub daty i godziny, spróbuj użyć as.character w zmiennych:

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

Na jednej lub obu zmiennych.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.