Considérez l'exemple suivant
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
Je voudrais agréger cette trame de données par semaine.
Autrement dit, supposons que je définisse une semaine comme commençant le lundi matin et se terminant le dimanche soir, que nous appellerons un Monday to Monday
cycle. (surtout, je veux pouvoir choisir d'autres conventions, comme du vendredi au vendredi par exemple).
Ensuite, je voudrais simplement compter la moyenne de values
pour chaque semaine.
Par exemple, dans l'exemple ci-dessus, on calculerait la moyenne de values
entre le lundi 24 février et le dimanche 2 mars, etc.
Comment puis je faire ça?
Merci!
EDIT: merci à tous ceux qui ont contribué à une idée. Un peu inhabituel, je pense que ma solution tardive est probablement plus appropriée ici. Merci encore!
Juste cette fois, après quelques recherches, je pense que j'ai trouvé une meilleure solution
Exemple ci-dessous pour les semaines commençant un jeudi. Les semaines seront étiquetées par leur premier jour d'un cycle donné.
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))
qui donne
> 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
Dans le sens inverse,
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
Ou utilisez isoweek
à la place:
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
Ou 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
que vous pouvez dire de commencer dimanche, si vous préférez:
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
Si vous souhaitez passer, disons, au mardi, ajoutez-en un à vos dates:
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
Les étiquettes seront toutefois désactivées. Si vous utilisez cut
, tenez compte des implications de son include.lowest
et right
paramètres, documentés à ?cut
.
pourquoi ne pas utiliser directement floor_date
et un entier pour ajuster la date de début de la semaine?
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
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
Cela utilise la fonction week
de lubrification et donne le numéro de semaine de la semaine de l'année.
Pour contrôler quel jour de la semaine est le jour de départ, reportez-vous à ce fil sur ce sujet:
Changer la fonction de lubrification pour qu'elle commence le lundi plutôt que le dimanche
La solution de ce thread par nograpes suggère que si vous voulez une version personnalisée de la fonction week()
en utilisant un jour arbitraire de la semaine comme début de semaine que vous venez de construire à partir de la base R comme ceci:
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"
À l'avenir, lubridate
aura cette option pour un jour de début arbitraire pendant des semaines, mais Hadley n'a pas encore réussi à l'ajouter ( https://github.com/hadley/lubridate/issues/257 ).