Подсчитать количество строк в каждой группе
У меня есть датафрейм, и я хотел бы посчитать количество строк в каждой группе. Я регулярно использую aggregate
функция суммирования данных следующим образом:
df2 <- aggregate(x ~ Year + Month, data = df1, sum)
Теперь я хотел бы посчитать наблюдения, но не могу найти подходящий аргумент для FUN
, Интуитивно я думал, что это будет следующим:
df2 <- aggregate(x ~ Year + Month, data = df1, count)
Но нет такой удачи.
Есть идеи?
Некоторые данные игрушки:
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))
20 ответов
Существует также df2 <- count(x, c('Year','Month'))
(пакет plyr)
Следуя совету @ Джошуа, вот один из способов подсчитать количество наблюдений в вашем df
кадр данных где Year
= 2007 и Month
= Ноябрь (если они столбцы):
nrow(df[,df$YEAR == 2007 & df$Month == "Nov"])
и с aggregate
, следуя @GregSnow:
aggregate(x ~ Year + Month, data = df, FUN = length)
Мы также можем использовать dplyr
,
Сначала немного данных:
df <- data.frame(x = rep(1:6, rep(c(1, 2, 3), 2)), year = 1993:2004, month = c(1, 1:11))
Теперь посчитаем:
library(dplyr)
count(df, year, month)
#piping
df %>% count(year, month)
Мы также можем использовать немного более длинную версию с трубопроводом и n()
функция:
df %>%
group_by(year, month) %>%
summarise(number = n())
или `функция подсчета:
df %>%
group_by(year, month) %>%
tally()
Старый вопрос без data.table
решение. Так что здесь идет...
С помощью .N
library(data.table)
DT <- data.table(df)
DT[, .N, by = list(year, month)]
Простой вариант для использования с aggregate
это length
функция, которая даст вам длину вектора в подмножестве. Иногда немного более надежно использовать function(x) sum( !is.na(x) )
,
Создать новую переменную Count
со значением 1 для каждой строки:
df1["Count"] <-1
Затем агрегируйте кадр данных, суммируя Count
колонка:
df2 <- aggregate(df1[c("Count")], by=list(year=df1$year, month=df1$month), FUN=sum, na.rm=TRUE)
Альтернатива aggregate()
функция в этом случае будет table()
с as.data.frame()
, который бы также указывал, какие комбинации года и месяца связаны с нулевыми вхождениями
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")]))
И без нуля встречающихся комбинаций
myAns[which(myAns$Freq>0),]
Если вы хотите включить 0 отсчетов за месяцы-годы, которые отсутствуют в данных, вы можете использовать немного table
магия.
data.frame(with(df1, table(Year, Month)))
Например, игрушечный data.frame в вопросе df1 не содержит наблюдений за январь 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
База R aggregate
функция не возвращает наблюдение за январь 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
Если вы хотите наблюдать за этим месяцем-годом с 0 в качестве счетчика, то приведенный выше код вернет data.frame со счетчиками для всех комбинаций месяц-год:
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
Для своих агрегаций я обычно заканчиваю тем, что хочу видеть среднее значение и "насколько велика эта группа" (то есть длина). Так что это мой удобный фрагмент для тех случаев;
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)
Решение SQL с использованием sqldf
пакет:
library(sqldf)
sqldf("SELECT Year, Month, COUNT(*) as Freq
FROM df1
GROUP BY Year, Month")
С помощью
collapse
пакет в
R
library(collapse)
library(magrittr)
df %>%
fgroup_by(year, month) %>%
fsummarise(number = fNobs(x))
library(tidyverse)
df_1 %>%
group_by(Year, Month) %>%
summarise(count= n())
Два очень быстрых варианта — это и .fcount
это быстрая версияdplyr::count
и использует тот же синтаксис. Вы можете использоватьadd = TRUE
чтобы добавить его как столбец (например):
library(collapse)
fcount(df1, Year, Month) #or df1 %>% fcount(Year, Month)
# Year Month N
# 1 2012 Feb 4
# 2 2014 Jan 3
# 3 2013 Mar 2
# 4 2013 Feb 2
# 5 2012 Jan 2
# 6 2012 Mar 2
# 7 2013 Jan 1
# 8 2014 Feb 3
# 9 2014 Mar 1
ближе кcollapse
исходный синтаксис. Сначала сгруппируйте данные с помощьюGRP
. Затем используйте . По умолчанию,GRPN
создает расширенный вектор, соответствующий исходным данным. (Вdplyr
, это было бы эквивалентно использованиюmutate
). Использоватьexpand = FALSE
для вывода суммированного вектора.
library(collapse)
GRPN(GRP(df1, .c(Year, Month)), expand = FALSE)
Микробенчмарк с кадром данных размером 100 000 x 3 и 4997 различными группами.collapse::fcount
намного быстрее, чем любой другой вариант.
library(collapse)
library(dplyr)
library(data.table)
library(microbenchmark)
set.seed(1)
df <- data.frame(x = gl(1000, 100),
y = rbinom(100000, 4, .5),
z = runif(100000))
dt <- df
mb <-
microbenchmark(
aggregate = aggregate(z ~ x + y, data = df, FUN = length),
count = count(df, x, y),
data.table = setDT(dt)[, .N, by = .(x, y)],
'collapse::fnobs' = df %>% fgroup_by(x, y) %>% fsummarise(number = fnobs(z)),
'collapse::GRPN' = GRPN(GRP(df, .c(x, y)), expand = FALSE),
'collapse::fcount' = fcount(df, x, y)
)
# Unit: milliseconds
# expr min lq mean median uq max neval
# aggregate 159.5459 203.87385 227.787186 223.93050 246.36025 335.0302 100
# count 55.1765 63.83560 74.715889 73.60195 79.20170 196.8888 100
# data.table 8.4483 15.57120 18.308277 18.10790 20.65460 31.2666 100
# collapse::fnobs 3.3325 4.16145 5.695979 5.18225 6.27720 22.7697 100
# collapse::GRPN 3.0254 3.80890 4.844727 4.59445 5.50995 13.6649 100
# collapse::fcount 1.2222 1.57395 3.087526 1.89540 2.47955 22.5756 100
Я обычно использую табличную функцию
df <- data.frame(a=rep(1:8,rep(c(1,2,3, 4),2)),year=2011:2021,month=c(1,3:10))
new_data <- as.data.frame(table(df[,c("year","month")]))
Учитывая ответ @Ben, R выдаст ошибку, если df1
не содержит x
колонка. Но это может быть решено элегантно с paste
:
aggregate(paste(Year, Month) ~ Year + Month, data = df1, FUN = NROW)
Точно так же это можно обобщить, если в группировке используется более двух переменных:
aggregate(paste(Year, Month, Day) ~ Year + Month + Day, data = df1, FUN = NROW)
Здесь уже есть множество замечательных ответов, но я хотел бы добавить еще 1 опцию для тех, кто хочет добавить новый столбец в исходный набор данных, который содержит количество повторений этой строки.
df1$counts <- sapply(X = paste(df1$Year, df1$Month),
FUN = function(x) { sum(paste(df1$Year, df1$Month) == x) })
То же самое может быть достигнуто путем сочетания любого из приведенных выше ответов с merge()
функция.
Ты можешь использовать by
функционирует как by(df1$Year, df1$Month, count)
это произведет список необходимой агрегации.
Вывод будет выглядеть так:
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
>
Вы также можете использоватьfcount
из моего пакета timeplyr, который принимает синтаксис dplyr, но использует свертывание под капотом.
library(collapse)
library(timeplyr)
library(dplyr)
library(data.table)
library(microbenchmark)
set.seed(1)
df <- data.frame(x = gl(1000, 100),
y = rbinom(100000, 4, .5),
z = runif(100000))
dt <- df
mb <-
microbenchmark(
aggregate = aggregate(z ~ x + y, data = df, FUN = length),
count = count(df, x, y),
data.table = setDT(dt)[, .N, by = .(x, y)],
'collapse::fcount' = collapse::fcount(df, x, y),
'timeplyr::fcount1' = timeplyr::fcount(df, x, y),
'timeplyr::fcount2' = timeplyr::fcount(df, .cols = c("x", "y"), order = FALSE)
)
mb
#> Unit: milliseconds
#> expr min lq mean median uq max
#> aggregate 84.0802 105.10615 123.593910 115.97675 134.65225 255.7676
#> count 40.8108 50.82485 60.718189 56.81630 68.85530 97.4791
#> data.table 3.7106 5.07485 6.273698 5.66645 6.44855 20.0465
#> collapse::fcount 1.0118 1.37400 1.915809 1.61105 2.08465 13.9825
#> timeplyr::fcount1 3.0390 3.74840 5.361852 4.56755 5.83405 44.0072
#> timeplyr::fcount2 1.3787 1.98625 2.640338 2.47025 3.03450 8.6333
#> neval
#> 100
#> 100
#> 100
#> 100
#> 100
#> 100
Создано 22 ноября 2023 г. с использованием reprex v2.0.2.
Если вы попробуете совокупные решения, указанные выше, и получите ошибку:
недопустимый тип (список) для переменной
Поскольку вы используете дату или дату и время, попробуйте использовать as.character для переменных:
aggregate(x ~ as.character(Year) + Month, data = df, FUN = length)
По одной или обеим переменным.
lw<- function(x){length(which(df$variable==someValue))}
agg<- aggregate(Var1~Var2+Var3, data=df, FUN=lw)
names(agg)<- c("Some", "Pretty", "Names", "Here")
View(agg)