Hitung jumlah baris dalam setiap kelompok

121

Saya memiliki kerangka data dan saya ingin menghitung jumlah baris dalam setiap grup. Saya biasanya menggunakan aggregatefungsi untuk menjumlahkan data sebagai berikut:

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

Sekarang, saya ingin menghitung pengamatan tetapi tidak dapat menemukan argumen yang tepat FUN. Secara intuitif, saya pikir itu akan menjadi sebagai berikut:

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

Tapi, tidak beruntung.

Ada ide?


Beberapa data mainan:

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))
MikeTP
sumber
17
nrow, NROW, length...
Joshua Ulrich
15
Saya terus membaca pertanyaan ini sebagai menanyakan cara yang menyenangkan untuk menghitung sesuatu (sebagai lawan dari banyak cara yang tidak benar, saya kira).
Hong Ooi
6
@JoshuaUlrich: nrowtidak bekerja untuk saya tetapi NROWdan lengthbekerja dengan baik. +1
Prolix

Jawaban:

69

Praktik terbaik saat ini (tidyverse) adalah:

require(dplyr)
df1 %>% count(Year, Month)
geotheory
sumber
Apakah ada cara untuk menggabungkan variabel dan melakukan penghitungan juga (seperti 2 fungsi dalam agregasi: mean + count)? Saya perlu mendapatkan rata-rata kolom dan jumlah baris untuk nilai yang sama di kolom lain
sop
1
Saya akan cbindhasil aggregate(Sepal.Length ~ Species, iris, mean)danaggregate(Sepal.Length ~ Species, iris, length)
geotheory
Saya telah melakukannya, tetapi tampaknya saya mendapatkan 2 kali setiap kolom kecuali kolom yang digabungkan; jadi saya telah melakukan penggabungan pada mereka dan tampaknya baik
sop
6
Saya tidak tahu tapi ini bisa berguna juga ...df %>% group_by(group, variable) %>% mutate(count = n())
Manoj Kumar
1
Ya, dplyr adalah praktik terbaik sekarang.
geotheory
67

Mengikuti saran @ Joshua, berikut salah satu cara Anda dapat menghitung jumlah observasi dalam dfkerangka data Anda di mana Year= 2007 dan Month= Nov (dengan asumsi mereka adalah kolom):

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

dan dengan aggregate, mengikuti @GregSnow:

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

dplyrpaket melakukan ini dengan count/ tallycommands, atau n()fungsinya :

Pertama, beberapa data:

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

Sekarang hitungannya:

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

Kami juga dapat menggunakan versi yang sedikit lebih panjang dengan pemipaan dan n()fungsinya:

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

atau tallyfungsinya:

df %>% 
  group_by(year, month) %>%
  tally()
jeremycg.dll
sumber
37

Pertanyaan lama tanpa data.tablesolusi. Jadi begini ...

Menggunakan .N

library(data.table)
DT <- data.table(df)
DT[, .N, by = list(year, month)]
mnel
sumber
1
standar saat ini untuk digunakan .()sebagai ganti list()dan setDT()untuk mengubah data.frame menjadi data.table. Jadi dalam satu langkah setDT(df)[, .N, by = .(year, month)].
sindri_baldur
23

Opsi sederhana untuk digunakan dengan aggregateadalah lengthfungsi yang akan memberi Anda panjang vektor dalam subset. Terkadang sedikit lebih kuat untuk digunakan function(x) sum( !is.na(x) ).

Greg Snow
sumber
18

Buat variabel baru Countdengan nilai 1 untuk setiap baris:

df1["Count"] <-1

Kemudian agregat dataframe, dijumlahkan dengan Countkolom:

df2 <- aggregate(df1[c("Count")], by=list(Year=df1$Year, Month=df1$Month), FUN=sum, na.rm=TRUE)
Leroy Tyrone
sumber
Hanya untuk catatan bahwa jika Anda menggunakan default, metode non-rumus untuk aggregate, tidak ada kebutuhan untuk mengubah nama masing-masing variabel dalam by=seperti list(year=df1$year)dll data.frameadalah listsudah begitu aggregate(df1[c("Count")], by=df1[c("Year", "Month")], FUN=sum, na.rm=TRUE)akan bekerja.
thelatemail
17

Alternatif untuk aggregate()fungsi dalam kasus ini adalah table()dengan as.data.frame(), yang juga akan menunjukkan kombinasi Tahun dan Bulan mana yang terkait dengan kejadian nol

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

Dan tanpa kombinasi yang terjadi nol

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

Jika Anda ingin memasukkan 0 hitungan bulan-tahun yang hilang dalam data, Anda dapat menggunakan sedikit tablekeajaiban.

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

Misalnya, mainan data.frame dalam pertanyaan, df1, tidak berisi observasi Januari 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

Fungsi dasar R aggregatetidak mengembalikan observasi untuk Januari 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

Jika Anda ingin pengamatan bulan-tahun ini dengan 0 sebagai hitungan, maka kode di atas akan mengembalikan data.frame dengan jumlah untuk semua kombinasi bulan-tahun:

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
lmo
sumber
5

Untuk kumpulan saya, saya biasanya ingin melihat arti dan "seberapa besar grup ini" (alias panjangnya). Jadi ini cuplikan praktis saya untuk kesempatan itu;

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)
labirin
sumber
4

SEBUAH solusi menggunakan sqldfpaket:

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

Mempertimbangkan jawaban @Ben, R akan membuat kesalahan jika df1tidak berisi xkolom. Tapi itu bisa diselesaikan dengan elegan dengan paste:

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

Demikian pula, dapat digeneralisasikan jika lebih dari dua variabel digunakan dalam pengelompokan:

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

Anda dapat menggunakan byfungsi karena by(df1$Year, df1$Month, count)itu akan menghasilkan daftar agregasi yang dibutuhkan.

Outputnya akan terlihat seperti,

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
> 
helcode
sumber
0

Sudah ada banyak jawaban bagus di sini, tetapi saya ingin menambahkan 1 opsi lagi bagi mereka yang ingin menambahkan kolom baru ke kumpulan data asli yang berisi berapa kali baris tersebut diulang.

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

Hal yang sama dapat dicapai dengan menggabungkan salah satu jawaban di atas dengan merge()fungsi.

filups21
sumber
0

Jika Anda mencoba solusi agregat di atas dan Anda mendapatkan kesalahan:

jenis tidak valid (daftar) untuk variabel

Karena Anda menggunakan stempel tanggal atau waktu, coba gunakan as.character pada variabel:

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

Pada satu atau kedua variabel.

Odiseus Ithaca
sumber