计算每个组内的行数

Count number of rows within each group

提问人:MikeTP 提问时间:3/22/2012 最后编辑:JaapMikeTP 更新时间:7/31/2023 访问量:356457

问:

我有一个数据帧,我想计算每个组中的行数。我经常使用该函数对数据求和,如下所示: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))
数据帧 聚合 R-FAQ SQL

评论

17赞 Joshua Ulrich 3/22/2012
nrow, , ...NROWlength
17赞 Hong Ooi 3/22/2012
我一直把这个问题看作是在寻求一种有趣的方法来计算事物(而不是许多无趣的方式,我猜)。
6赞 Prolix 8/11/2015
@JoshuaUlrich:对我不起作用,但工作正常。+1nrowNROWlength

答:

85赞 Ben 3/22/2012 #1

根据 @Joshua 的建议,您可以通过以下方法计算数据帧中的观测值数,其中 = 2007 和 = Nov(假设它们是列):dfYearMonth

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

和 ,以下@GregSnow:aggregate

aggregate(x ~ Year + Month, data = df, FUN = length)
25赞 Greg Snow 3/22/2012 #2

使用的简单选项是函数,它将为您提供子集中向量的长度。有时更健壮的是使用 .aggregatelengthfunction(x) sum( !is.na(x) )

19赞 BenBarnes 3/22/2012 #3

在这种情况下,该函数的替代方法是 ,它还指示 Year 和 Month 的哪些组合与零出现相关联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),]
102赞 geotheory 6/5/2013 #4

tidyverse/dplyr 方式:

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

评论

0赞 sop 5/15/2015
有没有办法聚合变量并进行计数(例如聚合中的 2 个函数:均值 + 计数)?我需要获取一列的平均值和其他列中相同值的行数
2赞 geotheory 5/17/2015
我的结果和cbindaggregate(Sepal.Length ~ Species, iris, mean)aggregate(Sepal.Length ~ Species, iris, length)
12赞 Manoj Kumar 12/15/2016
我不知道,但这也可能有用......df %>% group_by(group, variable) %>% mutate(count = n())
3赞 geotheory 12/15/2016
是的,dplyr 现在是最佳实践。
4赞 camille 9/11/2021
我是日常 dplyr 用户,但仍然不会称其为最佳实践,更像是常见的个人偏好
22赞 L Tyrone 8/2/2013 #5

为每行创建一个值为 1 的新变量:Count

df1["Count"] <-1

然后聚合 DataFrame,按列求和:Count

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

评论

0赞 thelatemail 7/18/2019
请注意,如果您使用的是默认的非公式方法,则无需重命名 like etc 中的每个变量。A 已经是 所以会工作。aggregateby=list(year=df1$year)data.framelistaggregate(df1[c("Count")], by=df1[c("Year", "Month")], FUN=sum, na.rm=TRUE)
44赞 mnel 8/2/2013 #6

一个没有解决方案的老问题。所以这里是......data.table

.N

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

评论

4赞 s_baldur 9/27/2019
现在的标准是使用 代替 data.frame 并将 data.frame 转换为 data.table。所以一步到位..()list()setDT()setDT(df)[, .N, by = .(year, month)]
0赞 IRTFM 11/18/2023
看到这一点,我想知道它是否解决了我使用 data.table 曾经的破坏者的问题。在 data.table 中尝试非常慢,这对我来说是一个巨大的难题。退休后,我把这个相当大的数据集抛在了脑后,所以无法回答这个问题。table
4赞 maze 1/6/2015 #7

对于我的聚合,我通常最终想要看到平均值和“这个群体有多大”(又名长度)。 所以这是我在这些场合的方便片段;

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)
60赞 jeremycg 8/13/2015 #8

dplyr 软件包使用 count/tally 命令或 n() 函数来执行此操作

首先,一些数据:

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

或函数:tally

df %>% 
  group_by(year, month) %>%
  tally()
8赞 lmo 3/1/2017 #9

如果要包含数据中缺少的月年计数为 0,则可以使用一点魔术。table

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

例如,问题 df1 中的玩具 data.frame 不包含 2014 年 1 月的观测值。

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 函数不返回 2014 年 1 月的观测值。aggregate

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
1赞 paudan 2/23/2018 #10

考虑到@Ben答案,如果 R 不包含列,则会抛出错误。但它可以通过以下方式优雅地解决:df1xpaste

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

同样,如果在分组中使用了两个以上的变量,则可以将其概括:

aggregate(paste(Year, Month, Day) ~ Year + Month + Day, data = df1, FUN = NROW)
5赞 M-- 5/30/2018 #11

使用包的 解决方案:sqldf

library(sqldf)
sqldf("SELECT Year, Month, COUNT(*) as Freq
       FROM df1
       GROUP BY Year, Month")
0赞 helcode 11/26/2018 #12

您可以使用函数,因为这将生成所需聚合的列表。byby(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
> 
0赞 filups21 5/17/2019 #13

这里已经有很多精彩的答案,但我想为那些想要向原始数据集添加包含该行重复次数的新列的人再添加一个选项。

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

通过将上述任何答案与函数相结合,也可以实现相同的目的。merge()

0赞 user5099519 11/28/2019 #14

如果您尝试上述聚合解决方案并收到错误:

变量的类型(列表)无效

由于您使用的是日期或日期时间戳,因此请尝试在变量上使用 as.character:

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

在一个或两个变量上。

3赞 woody70 11/27/2020 #15
library(tidyverse)

df_1 %>%
  group_by(Year, Month) %>%
  summarise(count= n()) 
5赞 akrun 3/17/2021 #16

collapseR

library(collapse)
library(magrittr)
df %>% 
    fgroup_by(year, month) %>%
    fsummarise(number = fNobs(x))
1赞 Ibrahimli 10/28/2021 #17

我通常使用表格功能


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

1赞 Maël 7/18/2023 #18

两个非常快速的选项是 和 。 是 的快速版本,并使用相同的语法。你可以用它来添加它作为列(-like):collapseGRPNfcountfcountdplyr::countadd = TRUEmutate

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

GRPN更接近 的原始语法。首先,使用 对数据进行分组。然后使用 .默认情况下,创建与原始数据匹配的扩展向量。(在 中,它相当于使用 )。用于输出汇总的向量。collapseGRPGRPNGRPNdplyrmutateexpand = 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

评论

1赞 IRTFM 11/18/2023
这真是令人印象深刻。我想知道为什么我没有看到更多使用折叠包的答案?
1赞 Maël 11/20/2023
是的,它的速度令人印象深刻,并且几乎具有数据操作所需的所有有用功能。它相对较新,就像任何其他语法一样,一开始就有点难以掌握,因此到目前为止,观众很胆怯,但我正在尝试用更多的解决方案填充 SO,尤其是在像这样浏览量最大的问题中。该软件包的作者 SebKrantz 也活跃在 SO 上。collapsecollapse
0赞 NicChr 11/23/2023
collapse 给我留下了深刻的印象,以至于我写了一个包“timeplyr”(在 CRAN 上)将 collapse 与 dplyr 语法相结合。具体见timeplyr::fcount()
0赞 NicChr 11/23/2023 #19

你也可以从我的包中使用 timeplyr,它接受 dplyr 语法,但在后台使用 collapse。fcount

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

创建于 2023-11-22 使用 reprex v2.0.2