2016-11-11 53 views
2

考虑下面的例子dplyr,lubridate:如何按星期汇总数据框?

library(tidyverse) 
library(lubridate) 
time <- seq(from =ymd("2014-02-24"),to= ymd("2014-03-20"), by="days") 
set.seed(123) 
values <- sample(seq(from = 20, to = 50, by = 5), size = length(time), replace = TRUE) 
df2 <- data_frame(time, values) 
df2 <- df2 %>% mutate(day_of_week = wday(time, label = TRUE)) 

Source: local data frame [25 x 3] 

     time values day_of_week 
     <date> <dbl>  <fctr> 
1 2014-02-24  30   Mon 
2 2014-02-25  45  Tues 
3 2014-02-26  30   Wed 
4 2014-02-27  50  Thurs 
5 2014-02-28  50   Fri 
6 2014-03-01  20   Sat 
7 2014-03-02  35   Sun 
8 2014-03-03  50   Mon 
9 2014-03-04  35  Tues 
10 2014-03-05  35   Wed 

我想通过周聚合该数据帧

也就是说,假设我定义一周为周一早上开始,周末晚上结束,我们将调用Monday to Monday周期。 (重要的是,我希望能够选择其他惯例,例如周五到周五)。

然后,我只想计算每周的values的平均值。

例如,在上面的例子中,可以计算在2月24日星期一到3月2日星期日之间的平均值values,依此类推。

我该怎么做?

谢谢!

编辑:感谢你们所有人提出了一个想法。有点不寻常,我认为我的晚期解决方案在这里可能更合适。再次感谢!

+2

'DF2%>%GROUP_BY(周=星期(时间))%>%总结(值=平均(值))',或使用'isoweek'代替。 – alistaire

+2

@Frank,完成,谢谢 –

+0

@alistaire感谢您的建议,但是您的解决方案无法控制整周周期。假设我想要周五到周五在这里循环。 –

回答

0

只是这一次,经过一番研究,我真的觉得我想出了一个更好的解决方案,

  • 给出正确的聚集
  • 给出正确的标签

例在星期四开始数周。这些周将标记为特定周期的第一天。

library(tidyverse) 
library(lubridate) 
options(tibble.print_min = 30) 

time <- seq(from =ymd("2014-02-24"),to= ymd("2014-03-20"), by="days") 
set.seed(123) 
values <- sample(seq(from = 20, to = 50, by = 5), size = length(time), replace = TRUE) 
df2 <- data_frame(time, values) 

df2 <- df2 %>% mutate(day_of_week_label = wday(time, label = TRUE), 
         day_of_week = wday(time, label = FALSE)) 

df2 <- df2 %>% mutate(thursday_cycle = time - ((as.integer(day_of_week) - 5) %% 7), 
         tmp_1 = (as.integer(day_of_week) - 5), 
         tmp_2 = ((as.integer(day_of_week) - 5) %% 7)) 

其给出

> df2 
# A tibble: 25 × 7 
     time values day_of_week_label day_of_week thursday_cycle tmp_1 tmp_2 
     <date> <dbl>    <ord>  <dbl>   <date> <dbl> <dbl> 
1 2014-02-24  30    Mon   2  2014-02-20 -3  4 
2 2014-02-25  45    Tues   3  2014-02-20 -2  5 
3 2014-02-26  30    Wed   4  2014-02-20 -1  6 
4 2014-02-27  50    Thurs   5  2014-02-27  0  0 
5 2014-02-28  50    Fri   6  2014-02-27  1  1 
6 2014-03-01  20    Sat   7  2014-02-27  2  2 
7 2014-03-02  35    Sun   1  2014-02-27 -4  3 
8 2014-03-03  50    Mon   2  2014-02-27 -3  4 
9 2014-03-04  35    Tues   3  2014-02-27 -2  5 
10 2014-03-05  35    Wed   4  2014-02-27 -1  6 
11 2014-03-06  50    Thurs   5  2014-03-06  0  0 
12 2014-03-07  35    Fri   6  2014-03-06  1  1 
13 2014-03-08  40    Sat   7  2014-03-06  2  2 
14 2014-03-09  40    Sun   1  2014-03-06 -4  3 
15 2014-03-10  20    Mon   2  2014-03-06 -3  4 
16 2014-03-11  50    Tues   3  2014-03-06 -2  5 
17 2014-03-12  25    Wed   4  2014-03-06 -1  6 
18 2014-03-13  20    Thurs   5  2014-03-13  0  0 
19 2014-03-14  30    Fri   6  2014-03-13  1  1 
20 2014-03-15  50    Sat   7  2014-03-13  2  2 
21 2014-03-16  50    Sun   1  2014-03-13 -4  3 
22 2014-03-17  40    Mon   2  2014-03-13 -3  4 
23 2014-03-18  40    Tues   3  2014-03-13 -2  5 
24 2014-03-19  50    Wed   4  2014-03-13 -1  6 
25 2014-03-20  40    Thurs   5  2014-03-20  0  0 
2
aggregate(df2$values,by=list(week(df2$time)),mean) 
Group.1  x 
1  8 30.00000 
2  9 40.00000 
3  10 36.42857 
4  11 37.85714 
5  12 43.33333 

本品采用lubridate的week功能,并给出一周的在今年的周数。

要控制在一周中的一天开始的第一天只是指这个线程上的话题:

Changing lubridate function to start on Monday rather than Sunday

从线程通过nograpes的解决方案表明,如果你想要的定制版本week()功能使用一周的任意一天作为一周的开始,您只需构建从基础R这样的:

start.of.week <- function(date) 
    date - (setNames(c(6,0:5),0:6) [strftime(date,'%w')]) 

end.of.week <- function(date) 
    date + (setNames(c(0,6:1),0:6) [strftime(date,'%w')]) 

start.of.week(as.Date(c('2014-01-05','2014-10-02','2014-09-22','2014-09-27'))) 
# "2013-12-30" "2014-09-29" "2014-09-22" "2014-09-22" 
end.of.week(as.Date(c('2014-01-05','2014-10-02','2014-09-22','2014-09-27'))) 
# "2014-01-05" "2014-10-05" "2014-09-28" "2014-09-28" 

未来lubridate将有一个任意的开始日期为几周的选项,但哈德利还没有到处添加它(https://github.com/hadley/lubridate/issues/257)。

+0

谢谢@ Hack-R,但您的解决方案无法控制周周期。此外,它不可能通过查看组标签来了解我们进入哪个星期 –

+1

@Noobie您在问题中请求的周周期。这是一年中的星期数。你怎么想这个星期被贴上标签? –

+0

好的,谢谢。标签并不重要,因为我总是可以连接年份数字。不过,假设我更喜欢周五到周五的周期。那我该如何调整你的解决方案呢? –

10

在tidyverse,

df2 %>% group_by(week = week(time)) %>% summarise(value = mean(values)) 

## # A tibble: 5 × 2 
## week value 
## <dbl> <dbl> 
## 1  8 37.50000 
## 2  9 38.57143 
## 3 10 38.57143 
## 4 11 36.42857 
## 5 12 45.00000 

或者使用isoweek代替:

df2 %>% group_by(week = isoweek(time)) %>% summarise(value = mean(values)) 

## # A tibble: 4 × 2 
## week value 
## <int> <dbl> 
## 1  9 37.14286 
## 2 10 40.71429 
## 3 11 35.00000 
## 4 12 42.50000 

或者cut.Date

df2 %>% group_by(week = cut(time, "week")) %>% summarise(value = mean(values)) 

## # A tibble: 4 × 2 
##   week value 
##  <fctr> <dbl> 
## 1 2014-02-24 37.14286 
## 2 2014-03-03 40.71429 
## 3 2014-03-10 35.00000 
## 4 2014-03-17 42.50000 

,你可以告诉在周日开始,如果你喜欢:

df2 %>% group_by(week = cut(time, "week", start.on.monday = FALSE)) %>% 
    summarise(value = mean(values)) 

## # A tibble: 4 × 2 
##   week value 
##  <fctr> <dbl> 
## 1 2014-02-23 37.50000 
## 2 2014-03-02 40.00000 
## 3 2014-03-09 33.57143 
## 4 2014-03-16 44.00000 

如果要转移,比如说,周二开始,添加一个日期:

df2 %>% group_by(week = cut(time + 1, "week")) %>% summarise(value = mean(values)) 

## # A tibble: 4 × 2 
##   week value 
##  <fctr> <dbl> 
## 1 2014-02-24 37.50000 
## 2 2014-03-03 40.00000 
## 3 2014-03-10 33.57143 
## 4 2014-03-17 44.00000 

标签将被关闭,但。如果使用cut,请考虑其include.lowestright参数的含义,记录在?cut

4

为什么不直接使用floor_date和一个整数来调整一周的开始日期?

library(lubridate) 
time <- seq(from =ymd("2014-02-24"),to= ymd("2014-03-20"), by="days") 

set.seed(123) 

values <- sample(seq(from = 20, to = 50, by = 5), size = length(time), replace = TRUE) 
df2 <- data_frame(time, values) 
df2 <- df2 %>% mutate(day_of_week = weekdays(time)) 

# week wednesday to tuesday 
df2 %>% group_by(Week = floor_date(time-3, unit="week")) %>% 
    summarize(WeeklyAveDist=mean(values), mean(values), min_date = min(time), max_date = max(time)) %>% mutate(weekdays(min_date), weekdays(max_date))) 

     Week WeeklyAveDist mean.values. min_date max_date 
1 2014-02-16  37.50000  37.50000 2014-02-24 2014-02-25 
2 2014-02-23  38.57143  38.57143 2014-02-26 2014-03-04 
3 2014-03-02  38.57143  38.57143 2014-03-05 2014-03-11 
4 2014-03-09  36.42857  36.42857 2014-03-12 2014-03-18 
5 2014-03-16  45.00000  45.00000 2014-03-19 2014-03-20 
    weekdays.min_date. weekdays.max_date. 
1    Monday   Tuesday 
2   Wednesday   Tuesday 
3   Wednesday   Tuesday 
4   Wednesday   Tuesday 
5   Wednesday   Thursday 


# Week Thursday to Wednesday 
df2 %>% group_by(Week = floor_date(time-4, unit="week")) %>% 
    summarize(WeeklyAveDist=mean(values), mean(values), min_date = min(time), max_date = max(time)) %>% mutate(weekdays(min_date), weekdays(max_date))) 

     Week WeeklyAveDist mean.values. min_date max_date 
1 2014-02-16  35.00000  35.00000 2014-02-24 2014-02-26 
2 2014-02-23  39.28571  39.28571 2014-02-27 2014-03-05 
3 2014-03-02  37.14286  37.14286 2014-03-06 2014-03-12 
4 2014-03-09  40.00000  40.00000 2014-03-13 2014-03-19 
5 2014-03-16  40.00000  40.00000 2014-03-20 2014-03-20 
    weekdays.min_date. weekdays.max_date. 
1    Monday   Wednesday 
2   Thursday   Wednesday 
3   Thursday   Wednesday 
4   Thursday   Wednesday 
5   Thursday   Thursday 
+0

这可能是最干净的。 –

+0

可以肯定,你能解释一下'floor_date(time-4,unit =“week”)'是做什么的? –

+1

从文档中,第50页:“floor_date获取日期 - 时间对象并将其舍入到指定的 时间单位的最近边界”。 https://cran.r-project.org/web/packages/lubridate/lubridate.pdf – vagabond