PREDICTION DE LA DEMANDE DE VELO
Ce fichier RMarkdown contient le rapport de l’analyse des données effectuée pour le projet de prévision de la demande quotidienne de location de vélos à l’aide de modèles de séries chronologiques dans R. Il contient des analyses telles que l’exploration de données, des statistiques récapitulatives et la construction de modèles de séries chronologiques. Le rapport final a été achevé le Mon Jan 22 14:23:47 2024.
Description des données:
Cet ensemble de données contient le décompte quotidien des transactions de location de vélos entre les années 2011 et 2012 dans le système Capital bikeshare avec les informations météorologiques et saisonnières correspondantes.
Source de données : https://archive.ics.uci.edu/ml/datasets/bike+sharing+dataset
Les packages
# charger les packages
library(readr)
library(data.table)
library(dplyr)
library(tidyverse)
library(ggplot2)
library(ggcorrplot)
library(plotly)
library(hrbrthemes)
library(viridis)
library(DT)
library(kableExtra)
library(lubridate)
library(quantmod)
library(highcharter)
# pour la corrélation
library(heatmaply)
library(ggcorrplot)
# pour le réchantillonnage
library(recipes)
library(themis)
# pour la construction des modèles
library(caret)
library(e1071)
library(glmnet)
library(rpart)
library(ISLR)
library(skimr)
library(MASS)
library(forecast)
library(forcats)
library(TSstudio)
library(psych)
importons les données
# days
day <- read_csv("C:/Users/adjeg/Downloads/PREDICTION_DELA_DEMANDE_DE_VELO/DATA/day.csv",)
head(day)
## # A tibble: 6 × 16
## instant dteday season yr mnth holiday weekday workingday weathersit
## <dbl> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 2011-01-01 1 0 1 0 6 0 2
## 2 2 2011-01-02 1 0 1 0 0 0 2
## 3 3 2011-01-03 1 0 1 0 1 1 1
## 4 4 2011-01-04 1 0 1 0 2 1 1
## 5 5 2011-01-05 1 0 1 0 3 1 1
## 6 6 2011-01-06 1 0 1 0 4 1 1
## # ℹ 7 more variables: temp <dbl>, atemp <dbl>, hum <dbl>, windspeed <dbl>,
## # casual <dbl>, registered <dbl>, cnt <dbl>
Nous lançons ce projet de prédiction de la demande quotidienne de vélos dans le cadre de projet COURSERA avec une forte motivation, cherchant activement des opportunités significatives. Le jeu de données “Bike Sharing” offre une vision moderne des systèmes de location de vélos, automatisant l’ensemble du processus. Notre objectif est de comprendre et de modéliser les modèles de comportement de location de vélos en exploitant des informations détaillées sur les conditions environnementales et saisonnières. En tant que chercheurs en quête d’opportunités, nous sommes motivés par le potentiel de ce projet à contribuer à des applications concrètes, tout en développant nos compétences et en explorant de nouvelles perspectives professionnelles.
data.table(names(day))
## V1
## 1: instant
## 2: dteday
## 3: season
## 4: yr
## 5: mnth
## 6: holiday
## 7: weekday
## 8: workingday
## 9: weathersit
## 10: temp
## 11: atemp
## 12: hum
## 13: windspeed
## 14: casual
## 15: registered
## 16: cnt
Le projet de prédiction de la demande quotidienne de vélos repose sur plusieurs variables. Voici une description succincte de chacune d’entre elles :
instant : Index d’enregistrement.
dteday : Date de l’enregistrement.
season : Saison (1: printemps, 2: été, 3: automne, 4:
hiver).
yr : Année (0: 2011, 1: 2012).
mnth : Mois (1 à 12).
hr : Heure (0 à 23).
holiday : Jour férié ou non.
weekday : Jour de la semaine.
workingday :Jour ouvrable (1 si ni weekend ni jour
férié, sinon 0).
weathersit : Situation météorologique (1: Clair,
quelques nuages, partiellement nuageux, 2: Brume + Nuageux, 3: Légère
neige, légère pluie + Orage + Nuages dispersés, 4: Fortes pluies +
Grésil + Orage + Brume, Neige + Brouillard).
temp : Température normalisée en Celsius (divisée par
41, max).
atemp : Température ressentie normalisée en Celsius
(divisée par 50, max).
hum : Humidité normalisée (divisée par 100, max).
windspeed : Vitesse du vent normalisée (divisée par 67,
max).
casual : Nombre d’utilisateurs occasionnels.
registered : Nombre d’utilisateurs enregistrés.
cnt : Nombre total de vélos loués (comprend à la fois
les utilisateurs occasionnels et enregistrés).
Ces variables sont essentielles pour comprendre les tendances de location de vélos et établir des modèles de prédiction basés sur les conditions environnementales et saisonnières.
dim(day)
## [1] 731 16
Nous examinons les dimensions de notre base de données avec la
commande dim(), nous donnant ainsi 7731 lignes et 16
colonnes pour notre base des données, fournissant une vue d’ensemble de
l’étendue de nos données.
length(day)
## [1] 16
Notre base de données contient 16 colones ou variables qui nouss aiderons à prédire la demande de vélo.
summary(day)
## instant dteday season yr
## Min. : 1.0 Min. :2011-01-01 Min. :1.000 Min. :0.0000
## 1st Qu.:183.5 1st Qu.:2011-07-02 1st Qu.:2.000 1st Qu.:0.0000
## Median :366.0 Median :2012-01-01 Median :3.000 Median :1.0000
## Mean :366.0 Mean :2012-01-01 Mean :2.497 Mean :0.5007
## 3rd Qu.:548.5 3rd Qu.:2012-07-01 3rd Qu.:3.000 3rd Qu.:1.0000
## Max. :731.0 Max. :2012-12-31 Max. :4.000 Max. :1.0000
## mnth holiday weekday workingday
## Min. : 1.00 Min. :0.00000 Min. :0.000 Min. :0.000
## 1st Qu.: 4.00 1st Qu.:0.00000 1st Qu.:1.000 1st Qu.:0.000
## Median : 7.00 Median :0.00000 Median :3.000 Median :1.000
## Mean : 6.52 Mean :0.02873 Mean :2.997 Mean :0.684
## 3rd Qu.:10.00 3rd Qu.:0.00000 3rd Qu.:5.000 3rd Qu.:1.000
## Max. :12.00 Max. :1.00000 Max. :6.000 Max. :1.000
## weathersit temp atemp hum
## Min. :1.000 Min. :0.05913 Min. :0.07907 Min. :0.0000
## 1st Qu.:1.000 1st Qu.:0.33708 1st Qu.:0.33784 1st Qu.:0.5200
## Median :1.000 Median :0.49833 Median :0.48673 Median :0.6267
## Mean :1.395 Mean :0.49538 Mean :0.47435 Mean :0.6279
## 3rd Qu.:2.000 3rd Qu.:0.65542 3rd Qu.:0.60860 3rd Qu.:0.7302
## Max. :3.000 Max. :0.86167 Max. :0.84090 Max. :0.9725
## windspeed casual registered cnt
## Min. :0.02239 Min. : 2.0 Min. : 20 Min. : 22
## 1st Qu.:0.13495 1st Qu.: 315.5 1st Qu.:2497 1st Qu.:3152
## Median :0.18097 Median : 713.0 Median :3662 Median :4548
## Mean :0.19049 Mean : 848.2 Mean :3656 Mean :4504
## 3rd Qu.:0.23321 3rd Qu.:1096.0 3rd Qu.:4776 3rd Qu.:5956
## Max. :0.50746 Max. :3410.0 Max. :6946 Max. :8714
Pour obtenir des statistiques descriptives détaillées, nous appliquons summary(). Cela nous fournit des informations telles que la moyenne, la médiane et d’autres indicateurs statistiques sur chaque colonne.
Vérification des types de données des colonnes: toutes las variables sont de type numéric.
(sapply(day, class))
## instant dteday season yr mnth holiday weekday
## "numeric" "Date" "numeric" "numeric" "numeric" "numeric" "numeric"
## workingday weathersit temp atemp hum windspeed casual
## "numeric" "numeric" "numeric" "numeric" "numeric" "numeric" "numeric"
## registered cnt
## "numeric" "numeric"
Verification des valeurs manquantes: il n’y a pas de valeur manquantes dans la base des données.
sum(is.na(day))
## [1] 0
Créeons la base des donnée pour explorer les données. Pour une analyse pertinente, il transformer la classe de certaines variables. Au lieu de classe numérique on va les transformer en variable catégorielle.
day_explore <- day
## la fonction pour transformer les variables
conv_cat <- function(data, cat_colone){
for(col in cat_colone){
data[[col]] <- as.factor(data[[col]])
}
return(data)
}
## transformons les variables
day_explore <- conv_cat(day_explore, c("season", "mnth", "holiday", "weekday", "workingday", "weathersit", "weathersit"))
day_explore$season <- factor(day_explore$season, levels = c(1, 2, 3, 4), labels = c("Printemps", "Été", "Automne", "Hiver"))
nb_saison <- day_explore %>% group_by(season) %>% summarise(total = sum(cnt))
kable(nb_saison, color = "red")
| season | total |
|---|---|
| Printemps | 471348 |
| Été | 918589 |
| Automne | 1061129 |
| Hiver | 841613 |
On a loué plus e vélo en automne et en été que les deux autres saisons.
day_explore$holiday <- factor(day_explore$holiday, levels = c(0, 1), labels = c("Jours ouvrables", "Jours Feriés"))
nb_holiday <- day_explore %>% group_by(holiday) %>% summarise(total = sum(cnt))
print(nb_holiday)
## # A tibble: 2 × 2
## holiday total
## <fct> <dbl>
## 1 Jours ouvrables 3214244
## 2 Jours Feriés 78435
day_explore$workingday <- factor(day_explore$workingday, levels = c(0, 1), labels = c( "weekend et jour férié", "ni weekend ni jour férié"))
nb_workingday <- day_explore %>% group_by(workingday) %>% summarise(nb = sum(cnt))
print(nb_workingday)
## # A tibble: 2 × 2
## workingday nb
## <fct> <dbl>
## 1 weekend et jour férié 1000269
## 2 ni weekend ni jour férié 2292410
Situation météorologique (1: Clair, quelques nuages, partiellement nuageux, 2: Brume + Nuageux, 3: Légère neige, légère pluie + Orage + Nuages dispersés, 4: Fortes pluies + Grésil + Orage + Brume, Neige + Brouillard).
day_explore$weathersit <- factor(day_explore$weathersit, levels = c(1, 2, 3), labels = c( "Clair", "Brume + Nuageux", "Légère neige, légère pluie + Orage"))
nb_weathersit <- day_explore %>% group_by(weathersit) %>% summarise(nb = sum(cnt))
print(nb_weathersit)
## # A tibble: 3 × 2
## weathersit nb
## <fct> <dbl>
## 1 Clair 2257952
## 2 Brume + Nuageux 996858
## 3 Légère neige, légère pluie + Orage 37869
# day_explore$mnth <- factor(day_explore$mnth, levels = c(1, 2, 3, 4, 5, 6, 7, 8,9,10, 11, 12), labels = c( month.name))
nb_mnth <- day_explore %>% group_by(mnth, yr) %>% summarise(nb=sum(cnt))
nb_mnth$mnth <- factor(nb_mnth$mnth, levels = 1:12, labels = c("Janvier", "Février", "Mars", "Avril", "Mai", "Juin", "Juillet", "Août", "Septembre", "Octobre", "Novembre", "Décembre"))
# Tracer le graphique
ggplot(nb_mnth, aes(x = mnth, y = nb)) +
geom_bar(stat = "identity", fill = "skyblue") + geom_text(aes(label = round(nb), vjust = -0.5), size = 3) +
labs(x = "Les mois de l'année", y = "Le nombre de locations de vélo", title = "Évolution du nombre de locations de vélo par mois entre 2011 et 2012") +
theme_minimal()
nb_weekday <- day_explore %>% group_by(weekday) %>% summarise(nb=sum(cnt))
nb_weekday$weekday <- factor(nb_weekday$weekday, levels = 0:6, labels = c("Dimanche", "Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi"))
print(nb_weekday)
## # A tibble: 7 × 2
## weekday nb
## <fct> <dbl>
## 1 Dimanche 444027
## 2 Lundi 455503
## 3 Mardi 469109
## 4 Mercredi 473048
## 5 Jeudi 485395
## 6 Vendredi 487790
## 7 Samedi 477807
# Tracer le graphique
ggplot(data = nb_weekday, aes(x=weekday, y=nb)) + geom_bar(stat = "identity", fill = "skyblue") + geom_text(aes(label = round(nb), vjust = -0.5), size = 3) +
labs(x = "Les jours de la semaine", y = "Le nombre de locations de vélo", title = "Évolution du nombre de locations de vélo par jour entre 2011 et 2012") +
theme_minimal()
nb_yr <- day_explore %>% group_by(yr) %>% summarise(nb=sum(cnt))
nb_yr$yr <- factor(nb_yr$yr, levels = 0:1, labels = c(2011, 2012))
print(nb_yr)
## # A tibble: 2 × 2
## yr nb
## <fct> <dbl>
## 1 2011 1243103
## 2 2012 2049576
# Tracer le graphique
ggplot(data = nb_yr, aes(x=yr, y=nb, fill=yr)) + geom_bar(stat = "identity") + geom_text(aes(label = round(nb), vjust = -0.5), size = 3, , position = position_stack(vjust = 0.5), size = 3) + coord_polar(theta = "y") +
labs(x = "L'année ", y = "Le nombre de locations de vélo", title = "Évolution du nombre de locations de vélo par année entre 2011 et 2012") +
theme_minimal()
On a loué plus 8000 vélo de plus que 2012 par raport à 2011 soit une augmentation de 65%.
C’est la variable cible que nous essayons de prédire. Nous devons analyser sa distribution, examiner les tendances temporelles et identifier s’il y a des saisons ou des jours particuliers avec une forte demande.
season
g_season <- ggplot(data = day_explore, aes(y = cnt, x=season, fill=season)) + geom_boxplot() + scale_fill_brewer(palette = "Set3") + xlab("Les saisons") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances sainsonnières de location de vélo")
ggplotly(g_season)
On loue plus de vélos en automne et en été plus qu’en hiver et printemps. Cidessous, on peut observer l’impact des types de jours sur la demande journalière de vélo.
holiday
g_holiday <- ggplot(data = day_explore, aes(y = cnt, x=holiday, fill=holiday)) + geom_boxplot() + scale_fill_brewer(palette = "Set3") + xlab("Les jours feriés") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction des jours fériés ou non")
ggplotly(g_holiday)
Le nombre de vélos loué varie en fonction des jours qu’il soit férié ou non, d’après le graphique cidessus, on a loué plus de vélo les jours ouvrables.
workingday
g_workingday <- ggplot(data = day_explore, aes(y = cnt, x=workingday, fill=workingday)) + geom_boxplot() + scale_fill_brewer(palette = "Set3") + xlab("Les jours ouvrables ou non ") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction des jours ouvrables ou non")
ggplotly(g_workingday)
weathersit :
g_weathersit <- ggplot(data = day_explore, aes(y = cnt, x=weathersit, fill=weathersit)) + geom_boxplot() + scale_fill_brewer(palette = "Set3") + xlab("Les jours d'intemperies") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction des jours d'intemperies")
ggplotly(g_weathersit)
On aloué plus de vélo pendant les jours clair que les autres jours où il y a des intemperies que ce soit la pluie, les orages, la neige et la verglass. Donc, les conditions météorologiques imapctent négativeent la demnade de vélo.
Relation entre le nombre de vélo loué et les variables
temp :, atemp :, hum :,
windspeed :, casual : ,
registered :
La température et la quantité de vélo loué
g_temp <- ggplot(data = day_explore, aes(x=temp, y = cnt, fill=season, color=season)) + geom_point() + scale_fill_brewer(palette = "Set3") + xlab("La température") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction de la température")
g_temp <- ggplot(data = day_explore, aes(x=temp, y = cnt)) + geom_point() + scale_fill_brewer(palette = "Set3") + xlab("La température") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction de la température")
g_temp <- g_temp + geom_smooth(method = "loess", se=F, color="blue")
## afficher
print(g_temp)
## affiche interactive
print(ggplotly(g_temp))
Plus la température est élevée, plus la location de vélo augmente. Ainsi, les saisons où il fait bon, il y a plus de vélos loués. Cependant, si la tempérture devient très élevée à la limite d’une canicaule, la demande de vélo tant à diminuer.
La température ressentie et la quantité de vélo loué
g_atemp <- ggplot(data = day_explore, aes(x=atemp, y = cnt)) + geom_line() + scale_fill_brewer(palette = "Set3") + xlab("La température ressentie") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction de la température ressentie")
g_atemp <- g_atemp + geom_smooth(method = "loess", se=F, color = "Blue")
ggplotly(g_atemp)
Dans l’ensemple on observe une tendance en croche de la demande de vélo au fur et à mésure que la température augmente. Cependant, une température plus élévée diminue aussi la demande de vélo.
L’humidité et la quantité de vélo loué
g_hum <- ggplot(data = day_explore, aes(x=hum, y = cnt)) + geom_point() + scale_fill_brewer(palette = "Set3") + xlab("Lhumidité") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction de l'humidité") + geom_smooth(method = "loess", se=F, color="blue")
ggplotly(g_hum)
Le graphique seul ne nous donne pas aaez d’information pour déduire la relation existante entre le nombre de vélo loué et l’humidité. Néanmoins, d’après la courbe des tendances, plus l’humidité est élevée moins il y a de location de vélo. On observe une tendance en cloche que celle de la température.
Relationentre la vitesse du vent normalisée et la demande de vélo
g_windspeed <- ggplot(data = day_explore, aes(x=windspeed, y = cnt)) + geom_point() + scale_fill_brewer(palette = "Set3") + xlab("La vitesse du vent") + ylab("Le nombr de velo loué par jour") + ggtitle("Les tendances de location de vélo en fonction de la vitesse du vent")
# Ajouter la courbe de tendance
g_windspeed <- g_windspeed + geom_smooth(method = "loess", se = T, color = "blue")
ggplotly(g_windspeed)
Plus, la vitesse du vent est faible, plus on loue de vélos. Cette affirmation reste à vérifier, la pente négative de la courbe de tendance révèle la relation décroissante qui existe entre le nombre de vélo loué et la viteese du vent.
Relation entre le nombre d’utilisateurs occasionnels et la quantité d evélo loué par jour
g_casual <- ggplot(data = day_explore, aes(x = casual, y = cnt)) +
geom_point(color = "red", size = 2, alpha = 0.5) +
xlab("Le nombre d'utilisateurs occasionnels") +
ylab("Le nombre de vélos loués par jour") +
ggtitle("Les tendances de location de vélo en fonction du nombre d'utilisateurs occasionnels")
# Ajouter la courbe de tendance
g_casual <- g_casual + geom_smooth(method = "loess", se = FALSE, color = "blue")
# Afficher le graphique
ggplotly(g_casual)
Dans l’ensemble, on observe une tendance croissante. Plus il y a d’utilisateurs auccasionnels, plus le nombre de vélo loué est important.
Relation entre le nombre d’utilisateurs enregistrés et le nombre de vélo loué
g_casual <- ggplot(data = day_explore, aes(x = casual, y = cnt)) +
geom_point(color = "red", size = 2, alpha = 0.5) +
xlab("Le nombre d'utilisateurs occasionnels") +
ylab("Le nombre de vélos loués par jour") +
ggtitle("Les tendances de location de vélo en fonction du nombre d'utilisateurs occasionnels")
# Ajouter la courbe de tendance
g_casual <- g_casual + geom_smooth(method = "loess", se = FALSE, color = "blue")
# Afficher le graphique
print(g_casual)
Corrélation entre les variables
cor_matrix <- cor(day[, -c(1:2)])
ggcorrplot(cor_matrix, hc.order = F, type = "lower", lab=TRUE, lab_size = 3)
nous_smoothed_data <- day %>%
ggplot(aes(x = dteday, y = cnt)) +
geom_line(color = "blue") +
geom_smooth(method = "loess", color = "red") +
labs(title = "Lissage des données de séries chronologiques",
x = "Date",
y = "Quantité de vélo")
print(nous_smoothed_data)
En général, on observe une tendace croissante de location de vélo de 2011 à 2012. Ainsi, on a des basses saisons et de hautes saisons de location de vélo. La haute saison comprend le mois de mai j’usqu’au mois de septembre.
Tendance Temporelle Générale :
Utilisez un graphique de ligne pour représenter le nombre total de vélos loués par jour au fil du temps (chronologie complète). Segmentez les données par mois ou trimestre pour identifier des schémas saisonniers ou des variations mensuelles.
day$dteday <- as.Date(day$dteday)
xts_data <- xts(day$cnt, order.by = day$dteday)
chartSeries(xts_data,
name = "Tendance de la location de vélo entre 2011 et 2012",
type = "line", # Type de graphique : ligne
main = "Tendance de la location de vélo",
ylab = "Nombre de vélos loués",
xlab = "Date"
)
Dans l’ensemle tout comme dans les analyse précédentes, on observe une tendance à la hausse. Mais au meme moment on a une tendance en forme de cloche pour chaque année. On va se concentrer sur la composition des données afin de distinguer les différentes composantes. On va essayer de segementer les données par saison.
month_data <- xts(day_explore$cnt, order.by = day_explore$dteday)
month_data <- (ts(month_data, frequency = 365))
decomposed_data <- decompose(month_data)
plot(decomposed_data)
Le résultat montre quatre graphiques de nos données de cours de location de voiture, à savoir :
Observé : tracé original des données de demande vélo
Tendance : mouvements à long terme de la moyenne. Sur ce graphique, nous pouvons voir la tendance à la hausse significative amorcée vers 2012.
Saisonnier : fluctuation saisonnière répétitive des données. La demande de vélo a eu tendance à atteindre son plus haut niveau en été et son plus bas niveau en janvier soit en hiver. En regardant cette tendance, on peut dire que globalement, le bon moment pour louer les vélos était en été (surtout en juin, juillet et aout) et le mauvais moment de l’année c’est en hivers (décembre, janvier et février).
Aléatoire : fluctuation irrégulière ou aléatoire non captée par la tendance et saisonnière.
Tendance temporelle entre la location de vélo et les situations météorologiques
day$cnt_normalise = (day$cnt / 10000)
highchart() %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = (day$cnt_normalise)), name = "Quantité de Vélo") %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$hum), name = "Humidité") %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$temp), name = "Température") %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$windspeed), name = "Vitesse du vent") %>% hc_xAxis(type = "datetime", dateTimeLabelFormats = list(day = "%e %b %Y")) %>%
hc_yAxis(title = list(text = "Valeurs")) %>%
hc_title(text = "Comparaison de la Quantité de Vélo, Humiditén, Température et Vitesse du vent") %>%
hc_legend(layout = "vertical", align = "right", verticalAlign = "middle")
On a quatre courbes interactives montrant l’impact de la météo sur la location de vélo:
La courbe du nombre de vélo loué en bleu
La curbe du niveau d’humidité en noir
La courbe de la température en vert
La courbe de la viteese du vent en orange
Dans l’ensemble les évements météorologiques ont un impact sigificative sur la demande de vélo vu la corrélation existante entre elles. Toute foids, la corrélation n’implique pas directement de causalité.
Tendance temporelle des interactions des clients sur le nombre de vélo loué
highchart() %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$cnt), name = "Quantité de vélo") %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$registered), name = "Nombre d'utilisateurs enregistrés") %>%
hc_add_series(day, "line", hcaes(x = day$dteday, y = day$casual), name = "Utilisateurs occasionels") %>%
hc_xAxis(type = "datetime", dateTimeLabelFormats = list(day = "%e %b %Y")) %>%
hc_yAxis(title = list(text = "Valeurs")) %>%
hc_title(text = "Evolution de la Quantité de Vélo, du Nombre d'utilisateurs enregistrés et des Utilisateurs occasionels") %>%
hc_legend(layout = "vertical", align = "right", verticalAlign = "middle")
On a trois courbes montrant l’évolution des comportements des clients sur la location de vélo. Le nombre d’utilisateurs occasionnels et le nombre de personnes enrégistrées sont en relation croissante avec le nombre de vélo louer par jour.
L’idée de la prévision des données de séries chronologiques est d’utiliser les données précédentes et présentes pour prédire l’avenir. Bien que tous les modèles utilisés pour prévoir ne puissent pas être précis à 100 %, le résultat peut généralement être très utile pour prendre des décisions concernant l’avenir. Il existe de nombreux modèles et algorithmes pouvant être utilisés pour prévoir les données de séries chronologiques, mais nous nous concentrerons uniquement sur la regression linéaire multiple, la méthode naïve et le modèle ARIMA dans cette discussion.
Avant de prévoir nos données de séries chronologiques, nous divisons d’abord nos données en données d’entraînement et de test. L’objectif est que nous puissions évaluer notre modèle en prédisant des données qui ne sont pas utilisées pour entraîner le modèle. En d’autres termes, nous pouvons dire que :
Train data : données utilisées pour ajuster le modèle
Données de test : données utilisées pour évaluer le modèle
En tant qu’analyste, nous devons déterminer un pourcentage de répartition qui peut représenter nos données d’entraînement et de test tout en ne nécessitant pas trop de coûts de calcul pour l’entraînement du modèle. Le pourcentage de répartition le plus courant est 80 % d’entraînement - 20 % de test, mais cela dépend quand même des données et également la finalité de nos prévisions.
Pour la régression multiple
set.seed(123)
n = 200
train <- head(day, -n)
test <- tail(day, n)
head(train)
## # A tibble: 6 × 17
## instant dteday season yr mnth holiday weekday workingday weathersit
## <dbl> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 1 2011-01-01 1 0 1 0 6 0 2
## 2 2 2011-01-02 1 0 1 0 0 0 2
## 3 3 2011-01-03 1 0 1 0 1 1 1
## 4 4 2011-01-04 1 0 1 0 2 1 1
## 5 5 2011-01-05 1 0 1 0 3 1 1
## 6 6 2011-01-06 1 0 1 0 4 1 1
## # ℹ 8 more variables: temp <dbl>, atemp <dbl>, hum <dbl>, windspeed <dbl>,
## # casual <dbl>, registered <dbl>, cnt <dbl>, cnt_normalise <dbl>
head(test)
## # A tibble: 6 × 17
## instant dteday season yr mnth holiday weekday workingday weathersit
## <dbl> <date> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 532 2012-06-15 2 1 6 0 5 1 1
## 2 533 2012-06-16 2 1 6 0 6 0 1
## 3 534 2012-06-17 2 1 6 0 0 0 1
## 4 535 2012-06-18 2 1 6 0 1 1 2
## 5 536 2012-06-19 2 1 6 0 2 1 1
## 6 537 2012-06-20 2 1 6 0 3 1 1
## # ℹ 8 more variables: temp <dbl>, atemp <dbl>, hum <dbl>, windspeed <dbl>,
## # casual <dbl>, registered <dbl>, cnt <dbl>, cnt_normalise <dbl>
test$dteday <- as.Date(test$dteday)
Préparation des données pour les modèles ARIMA
# tranformer les données en time serie
data_ts = ts(day$cnt, start = c(2011, 1), frequency = 365)
# partition des données
partition <- ts_split(data_ts)
train_ts <- partition$train
test_ts <- partition$test
Avant la prédiction, faison une régression multiple pour identifier les variables qui contribue à l’explication du nombre de vélo loué par jour.
reg_multi = lm(cnt ~., data = train)
summary(reg_multi)
##
## Call:
## lm(formula = cnt ~ ., data = train)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.070e-11 -2.360e-13 7.100e-14 3.290e-13 1.071e-11
##
## Coefficients: (2 not defined because of singularities)
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) -8.947e-13 8.422e-13 -1.062e+00 0.288559
## instant 1.340e-14 1.213e-14 1.104e+00 0.270014
## dteday NA NA NA NA
## season -2.674e-13 2.113e-13 -1.265e+00 0.206394
## yr -5.733e-12 4.468e-12 -1.283e+00 0.200030
## mnth -4.713e-13 3.718e-13 -1.268e+00 0.205523
## holiday -4.287e-13 6.704e-13 -6.390e-01 0.522784
## weekday -1.033e-13 5.388e-14 -1.917e+00 0.055755 .
## workingday -8.642e-13 3.987e-13 -2.168e+00 0.030647 *
## weathersit 9.007e-13 2.651e-13 3.398e+00 0.000732 ***
## temp 1.651e-11 7.392e-12 2.234e+00 0.025936 *
## atemp -1.708e-11 8.357e-12 -2.044e+00 0.041504 *
## hum -9.709e-13 9.940e-13 -9.770e-01 0.329115
## windspeed 0.000e+00 1.551e-12 0.000e+00 1.000000
## casual 1.000e+00 2.980e-16 3.356e+15 < 2e-16 ***
## registered 1.000e+00 2.017e-16 4.959e+15 < 2e-16 ***
## cnt_normalise NA NA NA NA
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.434e-12 on 516 degrees of freedom
## Multiple R-squared: 1, Adjusted R-squared: 1
## F-statistic: 1.777e+31 on 14 and 516 DF, p-value: < 2.2e-16
# prédiction sur les données de test
prediction = predict(reg_multi, newdata = test)
fc_multi <- forecast(reg_multi, newdata = test, h=365)
test$prediction = predict(reg_multi, newdata = test)
ts_plot(
test[c("dteday", "cnt", "prediction")],
title = "Quantité de vélo loué et prédiction de vélo loué")
La courbe de la quantité de louer est confondue à la courbe de la prédiction.
mape = mean(abs(test$cnt - test$prediction) / test$cnt)
print(mape)
## [1] 1.141422e-15
Plus l’erreur est faible mieus c’est. Donc, si on construit un nouveau modèle, son erreur doit etre en dessous de celles de la régression linéeaire.
Au vu des résultats de la régression et d’après le coefficient de
détermination, les variables explicatiquent 100% des variabilités de la
quantité de vélo louer par jour. Et d’après le fisher, l’ensemble des
estimateurs sont significatifs. Le modèle prédit sans faute les données
de tests. Néanmois, les estimateurs de certaines variables comme :
la saison, les jours feriés, le mois, l'année, l'humidité et la vitesse du vent
ne sont pas significative. Ce problèle peut etre la source d’une
multicolinéarité entre les varibles explicatives ou d’une
autocorrélation des résidus.
La méthode naïve est une méthode de prévision qui utilise la dernière observation comme résultat prévisionnel de nos données. Il est utilisé comme modèle de base dans les prévisions. Si le résultat de notre modèle est moins bon que celui de la méthode naïve, nous préférerons ne pas utiliser notre modèle.
prediction_naive<- naive(train_ts)
print(prediction_naive)
## Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
## 2012.4027 6536 5266.077 7805.923 4593.8198 8478.180
## 2012.4055 6536 4740.057 8331.943 3789.3425 9282.658
## 2012.4082 6536 4336.428 8735.572 3172.0453 9899.955
## 2012.4110 6536 3996.153 9075.847 2651.6397 10420.360
## 2012.4137 6536 3696.365 9375.635 2193.1531 10878.847
## 2012.4164 6536 3425.336 9646.664 1778.6496 11293.350
## 2012.4192 6536 3176.099 9895.901 1397.4743 11674.526
## 2012.4219 6536 2944.114 10127.886 1042.6849 12029.315
## 2012.4247 6536 2726.230 10345.770 709.4595 12362.540
## 2012.4274 6536 2520.150 10551.850 394.2871 12677.713
autoplot(prediction_naive)
La ligne bleue est la moyenne de notre prédiction, tandis que les zones plus sombres et plus claires représentent respectivement des intervalles de confiance de 80 % et 95 %. Si nous comparons le résultat aux données réelles du test, nous pouvons voir qu’il existe des différences entre eux.
Les modèles ARIMA (AutoRegressive Integrated Moving Average) constituent une classe de modèles statistiques largement utilisée dans notre domaine pour modéliser et prévoir des séries chronologiques temporelles. Nous les utilisons pour combiner les composants d’autorégression (AR), d’intégration (I) et de moyenne mobile (MA), afin de capturer les motifs temporels et les tendances dans nos données.
Voici une brève description des composants ARIMA que nous intégrons dans notre approche :
Composante AutoRegressive (AR) :
Composante d’Intégration (I) :
Composante Moving Average (MA) :
Notre modèle ARIMA est défini par trois paramètres principaux : - p (ordre de l’autorégression) : le nombre de retards inclus dans notre modèle AR. - d (ordre d’intégration) : le nombre de différenciations nécessaires pour rendre notre série stationnaire. - q (ordre de la moyenne mobile) : le nombre de termes de moyenne mobile inclus dans notre modèle MA.
En résumé, nous utilisons les modèles ARIMA pour modéliser nos séries temporelles en tenant compte de la dépendance temporelle, des tendances et des irrégularités. Ces modèles sont essentiels dans notre approche pour la prévision de séries temporelles, la détection de tendances et l’analyse approfondie de nos données temporelles.
# construction du modèle
model_arima <- auto.arima(train_ts, seasonal = FALSE)
print(model_arima)
## Series: train_ts
## ARIMA(0,1,2) with drift
##
## Coefficients:
## ma1 ma2 drift
## -0.6033 -0.2409 10.2582
## s.e. 0.0410 0.0398 5.8496
##
## sigma^2 = 705347: log likelihood = -4164.81
## AIC=8337.62 AICc=8337.7 BIC=8354.56
# prédire les n périodes des données
prediction_ns <- forecast(model_arima, h=365)
# rerésentation graphique des résultats
autoplot(prediction_ns)
Le résultat en utilisant ARIMA non saisonnier est une donnée de tendance à la hausse. Cependant, si nous les comparons aux données de test réelles, il existe encore quelques différences entre elles.
# modèle saisonnier
model_arima_s <- auto.arima(train_ts, seasonal = TRUE)
print(model_arima_s)
## Series: train_ts
## ARIMA(0,1,2) with drift
##
## Coefficients:
## ma1 ma2 drift
## -0.6033 -0.2409 10.2582
## s.e. 0.0410 0.0398 5.8496
##
## sigma^2 = 705347: log likelihood = -4164.81
## AIC=8337.62 AICc=8337.7 BIC=8354.56
# Prédiction des n périodes
prediction_s <- forecast(model_arima_s, h=365)
# représentation graphique
autoplot(prediction_s)
Il s’avère que que nous incluions ou non une partie saisonnière de nos données, la fonction auto.arima() produit le même résultat. Cela signifie que la partie saisonnière de nos données n’est pas significative, de sorte qu’ARIMA non saisonnière est le meilleur modèle ARIMA basé sur auto.arima() pour notre ensemble de données.
Après avoir prévu nos données, la dernière étape consiste à évaluer nos prévisions. L’évaluation des prévisions est effectuée en vérifiant si les résidus répondent aux hypothèses résiduelles et en comparant les mesures de précision.
Le résiduel est la différence entre les données prévues et les données réelles. Un bon modèle doit avoir un résidu distribué de manière aléatoire sans modèle évident. Voici quelques hypothèses résiduelles qui doivent être respectées :
Normalement distribué (moyenne = 0) qui peut être vérifié à l’aide d’une courbe normale. La courbe normale doit être en forme de cloche.
Avoir une variance constante qui peut être vérifiée à l’aide d’un tracé résiduel. Une variance constante est représentée par une fluctuation constante des données.
Il n’y a pas d’autocorrélation qui peut être vérifiée à l’aide du tracé ACF et du test Ljung Box. L’autocorrélation peut être détectée dans le tracé ACF lorsqu’il y a des lignes au-delà de la limite supérieure ou inférieure. Dans le test de Ljung Box, pour répondre à cette hypothèse, nous devons avoir une valeur p supérieure à 0,05. Si le résultat du tracé ACF et du test Ljung Box est différent, nous préférerons utiliser le résultat du test Ljung Box.
checkresiduals(reg_multi)
##
## Breusch-Godfrey test for serial correlation of order up to 20
##
## data: Residuals
## LM test = 58.72, df = 20, p-value = 1.122e-05
Dans notre analyse, le test de Breusch-Godfrey a été utilisé pour
évaluer la présence d’autocorrélation sérielle dans les résidus du
modèle reg_multi . Nous avons étendu le test jusqu’à un
ordre de 20. Les résultats montrent une statistique de test (LM test) de
58.72, avec 20 degrés de liberté, et un p-value de 1.122e-05 (ou
0.00001122), bien en dessous du seuil communément utilisé de 0.05.
En interprétant ces résultats, nous concluons que nous disposons de suffisamment de preuves pour rejeter l’hypothèse nulle selon laquelle il n’y a pas d’autocorrélation sérielle dans les résidus jusqu’à l’ordre 20. Autrement dit, les résultats suggèrent une autocorrélation significative des résidus à plusieurs retards.
Cette constatation peut indiquer que le modèle actuel ne capture pas pleinement la structure temporelle des données. Il serait donc judicieux d’examiner visuellement les résidus et de considérer d’éventuels ajustements au modèle pour mieux rendre compte de la structure temporelle des données.
checkresiduals(prediction_naive)
##
## Ljung-Box test
##
## data: Residuals from Naive method
## Q* = 224.95, df = 102, p-value = 2.971e-11
##
## Model df: 0. Total lags used: 102
Dans notre analyse, le test de Ljung-Box a été utilisé pour évaluer
l’autocorrélation des résidus du modèle prediction_naive,
en particulier ici, un modèle utilisant la méthode naïve. Les résultats
montrent une statistique de test (Q*) de 224.95, avec 102 degrés de
liberté, et un p-value de 2.971e-11 (ou 0.00000000002971), ce qui est
nettement inférieur au seuil communément utilisé de 0.05.
En interprétant ces résultats, nous concluons que nous disposons de suffisamment de preuves pour rejeter l’hypothèse nulle selon laquelle il n’y a pas d’autocorrélation dans les résidus. Autrement dit, les résultats suggèrent une autocorrélation significative des résidus.
Cette constatation peut indiquer que la méthode naïve utilisée dans le modèle actuel n’a pas réussi à capturer pleinement la structure temporelle des données, conduisant à des résidus présentant une autocorrélation significative. Il serait donc nécessaire de revoir le modèle et d’explorer des approches alternatives pour mieux modéliser la série temporelle.
prediction_ns <- forecast(model_arima, h=365)
checkresiduals(prediction_ns)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,2) with drift
## Q* = 121.76, df = 100, p-value = 0.06867
##
## Model df: 2. Total lags used: 102
Dans notre analyse du modèle ARIMA(0,1,2) with drift, le test de Ljung-Box a été utilisé pour évaluer l’autocorrélation des résidus. Les résultats montrent une statistique de test (Q*) de 121.76, avec 100 degrés de liberté, et un p-value de 0.06867.
Interprétation :
La statistique de test (Q*) est le test de Ljung-Box pour les résidus du modèle. Elle mesure l’autocorrélation des résidus jusqu’à un certain nombre de lags. Les degrés de liberté (df) indiquent le nombre de lags inclus dans le test. Le p-value est la probabilité d’observer une statistique de test aussi extrême que celle observée, sous l’hypothèse nulle que les résidus sont indépendants. Dans notre cas, le p-value est supérieur au seuil communément utilisé de 0.05. Cela suggère que nous n’avons pas suffisamment de preuves pour rejeter l’hypothèse nulle d’absence d’autocorrélation dans les résidus. Autrement dit, les résidus du modèle ARIMA semblent ne pas présenter une autocorrélation significative.
Cela peut indiquer que le modèle ARIMA a bien capturé la structure temporelle de la série, laissant des résidus qui ne montrent pas de schéma d’autocorrélation significatif. Cependant, il est toujours important de considérer d’autres aspects du modèle et de vérifier si les résidus satisfont aux hypothèses du modèle.
checkresiduals(prediction_s)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(0,1,2) with drift
## Q* = 121.76, df = 100, p-value = 0.06867
##
## Model df: 2. Total lags used: 102
Les résultats du test de Ljung-Box pour les résidus du modèle ARIMA saisonnier (ARIMA(0,1,2) with drift) indiquent une statistique de test (Q*) de 121.76, avec 100 degrés de liberté, et un p-value de 0.06867.
Dans ce cas, le p-value est supérieur au seuil communément utilisé de 0.05. Cela suggère que nous n’avons pas suffisamment de preuves pour rejeter l’hypothèse nulle d’absence d’autocorrélation dans les résidus. Autrement dit, les résidus du modèle ARIMA saisonnier semblent ne pas présenter une autocorrélation significative.
Cela peut indiquer que le modèle ARIMA saisonnier a bien capturé la structure temporelle de la série, laissant des résidus qui ne montrent pas de schéma d’autocorrélation significatif. Toutefois, il est toujours essentiel de considérer d’autres aspects du modèle et de vérifier si les résidus satisfont aux hypothèses du modèle.
Cela pourrait inclure l’utilisation d’un modèle plus complexe, l’ajout de termes autorégressifs supplémentaires, ou l’exploration d’autres méthodes pour traiter l’autocorrélation dans les résidus. En général, l’autocorrélation des résidus peut indiquer que le modèle ne capture pas complètement la structure temporelle des données.
D’après les résultats, nous savons que la méthode naïve
et lm n’ont pas satisfait à l’hypothèse d’absence
d’autocorrélation, alors qu’ARIMA a satisfait à toutes les hypothèses.
Ainsi, sur la base de la vérification résiduelle, notre modèle ARIMA a
produit de meilleurs résultats que la méthode Naive, ce qui est une
bonne chose.
Il existe de nombreuses mesures de précision dans les prévisions. Dans cette discussion, nous comparerons l’erreur quadratique moyenne (RMSE) des deux modèles.
Erreur quadratique moyenne (RMSE) : l’écart type du résidu qui mesure l’étalement de nos résidus. Une valeur inférieure du RMSE est le signe d’un meilleur résultat.
prediction_s <- forecast(model_arima_s, h=365)
prediction_ns <- forecast(model_arima, h=365)
accuracy_naive <- accuracy(prediction_naive)
accuracy_ARIMA_SAISONNIER <- accuracy(prediction_s)
accuracy_ARIMA <- accuracy(prediction_ns)
TABLEAU_ACCURAcy <- datatable(bind_rows(
data.frame(MODELE = "NAIVE", accuracy_naive),
data.frame(MODELE = "ARIMA_S", accuracy_ARIMA_SAISONNIER),
data.frame(MODELE = "ARIMA", accuracy_ARIMA)), callback = JS("return table;"), width = 500,
height = 500)
TABLEAU_ACCURAcy
Sur la base des métriques cidessus, nous pouvons prendre en considération plusieurs aspects pour choisir le meilleur modèle. Voici une analyse des métriques pour chaque modèle :
ME (Mean Error)
RMSE (Root Mean Squared Error)
MAE (Mean Absolute Error)
MPE (Mean Percentage Error)
MAPE (Mean Absolute Percentage Error)
MASE (Mean Absolute Scaled Error)
*ACF1 (Autocorrelation of Errors)
En se basant sur ces métriques, le modèle ARIMA_S (ARIMA saisonnier) semble être le meilleur choix, car il a des valeurs relativement inférieures pour la plupart des métriques d’erreur par rapport au modèle Naive.
Le processus de location de vélos en libre-service est fortement corrélé aux paramètres environnementaux et saisonniers. Par exemple, les conditions météorologiques, les précipitations, le jour de la semaine, la saison, l’heure de la journée, etc. peuvent affecter les comportements de location.
Les données de séries chronologiques sont omniprésentes et la plupart d’entre elles peuvent affecter notre décision. Outre le cours de la demande de vélo dont nous avons discuté tout au long de cet projet, il existe certainement de nombreux autres exemples. Pour un homme d’affaires propriétaire d’un grand magasin, les données de ventes doivent constituer une série chronologique importante qui oriente sa décision commerciale. Nous pouvons également analyser les données économiques, environnementales et prévoir les données de ventes pour aider un homme d’affaires à prendre sa décision.
La décomposition des données de séries chronologiques peut nous donner une vue plus détaillée de la structure de nos données. L’analyser nous aidera à prendre des décisions concernant nos données. Cependant, la décomposition dans R ne peut être effectuée que sur l’objet dont la fréquence a été spécifiée.
Après avoir analysé nos données de séries chronologiques, nous souhaitons généralement les prévoir pour nous aider à prendre une décision concernant l’avenir. Cependant, gardez à l’esprit que le résultat d’une prévision ne peut jamais être précis à 100 %, nous devons donc avoir un deuxième plan pour la décision future. La prévision peut être effectuée à l’aide de nombreux modèles et algorithmes. Dans cet projet, nous avons discuté du modèle de régression linéaire multiple, de la méthode naïve et du modèle ARIMA.
La méthode naïve est un excellent outil pour devenir une référence pour nos autres modèles et une méthode très simple car nous utilisons uniquement la dernière observation comme résultat de prévision. Bien que dans certains cas, le résultat prévisionnel de cette méthode puisse être utile (par exemple : un vendeur qui vise que ses ventes du mois prochain soient les mêmes que celles de ce mois-ci), il est néanmoins suggéré d’utiliser une autre approche plus robuste pour traiter d’autres cas. . D’un autre côté, le modèle ARIMA (y compris le modèle saisonnier) peut être un bon modèle pour prévoir des données plus fluctuantes. Cependant, ce modèle ne peut être utilisé que pour des données pouvant être différenciées pour atteindre la stationnarité. Il existe de nombreux autres modèles qui peuvent peut-être donner un meilleur résultat pour votre ensemble de données, alors n’hésitez pas à en explorer davantage !
``Merci``