R - 按因子计算每日数值在特定范围内的数量,并按年汇总

4

我有每日数据,并且我想计算每年每天测量值在特定范围内的次数。该数据还按因素分组,因此我需要知道每个因素每年在某个范围内的天数(例如15至18)。

我有超过100年的大型数据集,但是这里仅提供此示例的一些数据:

Date <- seq(as.Date("2010/01/01"), by = "day", length.out = 1095)
People <- sample.int(20, 1095, replace = TRUE)
Country <- sample(x = c("Australia", "Canada", "France"), size = 1095, replace = TRUE)

mydf <- data.frame(Date, People, Country)

我希望了解每个国家每年“People”值在15到18之间的次数。
因此,我的输出将是一个新的数据框,类似于:
myDate    People    Country
2010      45        Australia
2010      10        Canada
2010      24        France
2011      33        Australia
2011      100       Canada
2011      4         France
2012      21        Australia
2012      66        Canada
2012      211       France

任何帮助都将不胜感激,因为我在这方面很困惑,已经寻找了答案,但是我找不到涉及日期和因子的解决方案。

2
在进行随机抽样时,始终使用set.seed()。因此以下答案的输出不同! - Parfait
4个回答

3
你可以使用 lubridatedplyr 实现它。使用 year() 获取年份并按年份和国家分组。最后一步是有条件的求和:
library(dplyr)
library(lubridate)

mydf %>%
  group_by(year = year(Date), Country) %>%
  summarise(p = sum(between(People, 15, 18)))


这可能会产生

   year Country       p
  <dbl> <fct>     <int>
1 2010. Australia    22
2 2010. Canada       34
3 2010. France       26
4 2011. Australia    21
5 2011. Canada       30
6 2011. France       13
7 2012. Australia    28
8 2012. Canada       31
9 2012. France       23

1
可以使用 summarise(p = sum(between(People, 15, 18)) - JasonAizkalns
你确定需要使用floor_date吗?我得到了错误的答案(一个单一值而不是按国家*年份分组的结果集)。 - IRTFM
@42-: 你说得对,这里不需要使用 floor_date()。老实说,我没有理解你的第二个问题——为什么会得到错误的答案?我使用你的 aggregate(...) 答案得到了完全相同的输出。 - Jan
啊哈,我还加载了plyr来回答另一个问题。plyr版本的summarise不同,并且给出了我所看到的结果。对于那个嘈杂的评论,我很抱歉。 - IRTFM

3

这里是必要的基本解决方案。关键点:使用 format.Date 将日期转换为字符年份值,并且按组分组需要是一个列表对象:

aggregate( mydf['People'], list(mydf[['Country']], format(mydf$Date, "%Y") ), 
                           FUN=function(d) sum( d >=15 & d <=18) )
    Group.1 Group.2 People
1 Australia    2010     25
2    Canada    2010     22
3    France    2010     24
4 Australia    2011     27
5    Canada    2011     19
6    France    2011     33
7 Australia    2012     19
8    Canada    2012     33
9    France    2012     24

如果您希望生成的数据框具有不同的列名,请将其添加到by-group定义中的列表中:

 aggregate( mydf['People'], list(Cntry=mydf[['Country']], Yr=format(mydf$Date, "%Y") ), 
                function(d) sum( d >=15 & d <=18) )
      Cntry   Yr People
1 Australia 2010     25
2    Canada 2010     22
3    France 2010     24
4 Australia 2011     27
5    Canada 2011     19
6    France 2011     33
7 Australia 2012     19
8    Canada 2012     33
9    France 2012     24

我正准备回来更改我的“aggregate”调用以进行布尔求和! - Parfait

2

有关 data.table 的解决方案:

library(data.table)
setDT(mydf)[,(People=sum(between(People, 15, 18))), by = .(year(Date), Country)]

   year   Country V1
1: 2010    Canada 22
2: 2010 Australia 17
3: 2010    France 22
4: 2011    Canada 23
5: 2011    France 22
6: 2011 Australia 26
7: 2012    Canada 21
8: 2012    France 29
9: 2012 Australia 26

1
考虑基础R聚合:
mydf$Year <- format(mydf$Date, "%Y")
mydf$NumberTime15_18 <- ifelse(mydf$People >= 15 & mydf$People <= 18, 1, 0)

aggregate(NumberTime15_18 ~ Country + Year, mydf, sum)

#     Country Year NumberTime15_18
# 1 Australia 2010              22
# 2    Canada 2010              17
# 3    France 2010              28
# 4 Australia 2011              26
# 5    Canada 2011              24
# 6    France 2011              20
# 7 Australia 2012              16
# 8    Canada 2012              27
# 9    France 2012              21

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接