2016-11-11 51 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