Data2
Groupe2
2025-04-21
1.Contexte du projet
Ce projet consiste à analyser une série temporelle représentant des volumes enregistrés au fil du temps. Nous allons charger les données, les
explorer, puis réaliser quelques traitements et visualisations statistiques.
2.Manipulation de la série temporelle
##2.1 Installation des packages nécessaires et Chargement des packages
if (!require("tidyverse")) install.packages("tidyverse")
if (!require("forecast")) install.packages("forecast")
if (!require("tseries")) install.packages("tseries")
if (!require("ggplot2")) install.packages("ggplot2")
library(tidyverse)
library(forecast)
library(tseries)
library(ggplot2)
3. Importation des données depuis le fichier
#install.packages("tinytex")
#tinytex::install_tinytex()
##3.1.Définir le chemin du fichier
chemin <- "C:/Users/razan/Downloads/volume_series.txt"
##3.2. Importation des données avec vérification
if (file.exists(chemin)) {
data <- read.table(chemin, header = FALSE, col.names = c("Date", "Volume"), fill = TRUE)
print(colnames(data)) # <-- vérifie bien les noms
message("Importation réussie")
} else {
stop("Fichier introuvable. Vérifiez le chemin.")
}
## [1] "Date" "Volume"
## Importation réussie
##3.3. Vérification du nombre d’observations
n_obs <- nrow(data)
message("Nombre d'observations: ", n_obs)
## Nombre d'observations: 1259
##3.4. Vérification des premières lignes
head(data)
——————————————-
4. Nettoyage des données
——————————————-
#4.1. # Vérification des valeurs manquantes
if (any(is.na(data))) {
na_count <- sum(is.na(data))
message("Valeurs manquantes détectées: ", na_count)
data <- na.omit(data) # Supprimer les lignes avec des NA
} else {
message("Aucune valeur manquante détectée")
}
## Aucune valeur manquante détectée
#4.2. Détection des outliers
# 4.2 Détection des outliers
# Fonction pour détecter les outliers
detect_outliers <- function(x) {
qnt <- quantile(x, probs = c(0.25, 0.75), na.rm = TRUE)
iqr <- 1.5 * IQR(x, na.rm = TRUE)
which(x < (qnt[1] - iqr) | x > (qnt[2] + iqr))
}
# S'assurer que Volume est bien numérique
data$Volume <- as.numeric(data$Volume)
## Warning: NAs introduits lors de la conversion automatique
# Supprimer les lignes contenant NA dans Volume (au cas où)
data <- data[!is.na(data$Volume), ]
# Application de la fonction
outliers_volume <- detect_outliers(data$Volume)
# Affichage des résultats
if (length(outliers_volume) > 0) {
cat("Indices des outliers :", outliers_volume, "\n")
cat("Valeurs des outliers :", data$Volume[outliers_volume], "\n")
} else {
cat("Aucun outlier détecté dans la colonne Volume.\n")
}
## Indices des outliers : 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 24 25 27 29 32 34 40 41 70 81 99 105 106 124 129
130 131 139 167 203 228 418 477 478 479 480 481 500 543 554 669 705 730 739 740 765 766 793 849 852 855 919 937 955 1146 117
5 1210 1235
## Valeurs des outliers : 72821100 70419300 65354400 56371600 93226400 92727400 87905900 81059800 81593200 85922700 84866200
78975200 82516700 75638200 64568100 57042300 63420300 77927200 57969900 67111700 62769000 51385100 52874300 52765600 5620370
0 51286600 53875900 52854700 54675800 67457000 51044000 78983000 57602200 58400300 59664100 52924300 55225300 51195600 63354
900 69870600 52588700 57984400 85731500 72848600 90428900 53481300 56989700 63477700 51033800 82543200 86102000 66526600 508
41400 54686000 54768800 69527400 64599200 64872700 69368900 58383700 55053800 52465100 78478200 55167100 53971000 64263700 5
4586300
#4.3. Affichage des résultats des outliers
if (length(outliers_volume) > 0) {
message("Outliers détectés dans la colonne 'Volume': ", length(outliers_volume))
# Remplacement des outliers par la médiane dans une fenêtre mobile
data_clean <- data
for (i in outliers_volume) {
window <- max(1, i-2):min(n_obs, i+2)
data_clean$Volume[i] <- median(data$Volume[window], na.rm = TRUE)
}
} else {
data_clean <- data
message("Aucun outlier détecté dans la colonne 'Volume'")
}
## Outliers détectés dans la colonne 'Volume': 67
——————————————-
5. Création de la série temporelle
——————————————-
#5.1. Création de la série temporelle
# Détection des outliers
outliers_indices <- detect_outliers(data_clean$Volume)
# Filtrer les outliers
data_clean_no_outliers <- data_clean[-outliers_indices, ]
ts_data <- ts(data_clean_no_outliers$Volume, start = c(2020, 3), frequency = 12)
print("Série temporelle créée sans les outliers.")
## [1] "Série temporelle créée sans les outliers."
#5.2. # Vérification des premières et dernières valeurs
print(head(ts_data))
## Mar Apr May Jun Jul Aug
## 2020 47817300 49630700 41243300 49630700 48318200 41905300
print(tail(ts_data))
## Jul Aug Sep Oct Nov Dec
## 2121 26443700 29387400 19619000 21127400 32845700 22955700
——————————————-
6. Exploration initiale
——————————————-
#6.1. Statistiques descriptives
cat("\nStatistiques descriptives:\n")
##
## Statistiques descriptives:
print(summary(ts_data))
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 7164500 20121475 24857150 26322857 31146025 49743700
cat("Écart-type:", sd(ts_data), "\n")
## Écart-type: 8313276
#6.2.Visualisation de la série temporelle
autoplot(ts_data) +
geom_line(color = "steelblue") +
labs(title = "Série temporelle des volumes de trading",
x = "Date",
y = "Volume") +
theme_minimal()
#6.3.Décomposition saisonnière
decomp <- stl(ts_data, s.window = "periodic")
autoplot(decomp) + ggtitle("Décomposition STL")
#6.4.Test de stationnarité
cat("\nTest de Dickey-Fuller augmenté:\n")
##
## Test de Dickey-Fuller augmenté:
print(adf.test(ts_data))
## Warning in adf.test(ts_data): p-value smaller than printed p-value
##
## Augmented Dickey-Fuller Test
##
## data: ts_data
## Dickey-Fuller = -7.0186, Lag order = 10, p-value = 0.01
## alternative hypothesis: stationary
cat("\nTest KPSS:\n")
##
## Test KPSS:
print(kpss.test(ts_data))
## Warning in kpss.test(ts_data): p-value smaller than printed p-value
##
## KPSS Test for Level Stationarity
##
## data: ts_data
## KPSS Level = 4.9118, Truncation lag parameter = 7, p-value = 0.01
——————————————-
7. Exportation des données nettoyées
——————————————-
#7.1. Exportation des données nettoyées
dates_export <- seq(from = as.Date("2020-03-01"), by = "month", length.out = length(ts_data))
write.csv(data.frame(
Date = format(dates_export, "%Y-%m-%d"),
Volume = as.numeric(ts_data)
), "donnees_nettoyees.csv", row.names = FALSE)
message("Données nettoyées exportées avec succès")
## Données nettoyées exportées avec succès
#7.2.Affichage des données nettoyées
#print(data_clean)
——————————————-
8. Analyse exploratoire approfondie
——————————————-
8.1. Visualisation globale avec tendance
autoplot(ts_data) +
geom_smooth(method = "loess", se = FALSE, color = "red", span = 0.3) +
labs(title = "Série temporelle avec tendance (lissage LOESS)",
x = "Temps", y = "Volume") +
theme_minimal()
## `geom_smooth()` using formula = 'y ~ x'
8.2. Décomposition avec STL déjà faite — on complète avec
les composantes
Déjà dans 5.3 : decomp <- stl(ts_data, s.window =
“periodic”)
Extraction des composantes
tendance <- decomp$time.series[, "trend"]
saisonnalite <- decomp$time.series[, "seasonal"]
residus <- decomp$time.series[, "remainder"]
Affichage des composantes séparément ( ✅feha prob
affichage)
par(mfrow = c(3, 1))
plot(tendance, main = "Composante tendance", col = "darkgreen", ylab = "Tendance")
plot(saisonnalite, main = "Composante saisonnière", col = "orange", ylab = "Saisonnalité")
plot(residus, main = "Composante résiduelle", col = "grey", ylab = "Résidus")
8.3. Visualisation de l’autocorrélation
acf(ts_data, main = "Fonction d'autocorrélation (ACF)")
pacf(ts_data, main = "Fonction d'autocorrélation partielle (PACF)")
8.4. Graphique saisonnier
ggseasonplot(ts_data, year.labels = TRUE, year.labels.left = TRUE) +
labs(title = "Graphique saisonnier", y = "Volume", x = "Mois") +
theme_minimal()
8.5. Boxplot par cycle annuel (par mois)
ggsubseriesplot(ts_data) +
labs(title = "Boxplot par sous-séries mensuelles", y = "Volume", x = "Mois") +
theme_minimal()
8.6. Analyse de tendance par régression linéaire
temps <- time(ts_data)
modele_tendance <- lm(ts_data ~ temps)
summary(modele_tendance)
##
## Call:
## lm(formula = ts_data ~ temps)
##
## Residuals:
## Min 1Q Median 3Q Max
## -19965155 -5385261 -1292015 4192937 25778089
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 267256911 15277509 17.49 <2e-16 ***
## temps -116335 7376 -15.77 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 7580000 on 1220 degrees of freedom
## Multiple R-squared: 0.1694, Adjusted R-squared: 0.1687
## F-statistic: 248.8 on 1 and 1220 DF, p-value: < 2.2e-16
Superposition de la tendance linéaire sur le graphe
autoplot(ts_data, series = "Données") +
autolayer(
ts(fitted(modele_tendance), start = start(ts_data), frequency = frequency(ts_data)),
series = "Tendance linéaire", color = "red"
) +
labs(title = "Tendance linéaire sur la série temporelle",
x = "Temps", y = "Volume") +
theme_minimal()
——————————————-
9. Étude de la stationnarité
——————————————-
##9.1 Installation et chargement des packages nécessaires
# Chargez les packages
library(ggplot2)
library(forecast)
library(tseries)
Exemple de série temporelle (à remplacer par tes vraies
données si besoin)
set.seed(123) ts_data <- ts(rnorm(100), frequency = 12) # données mensuelles fictives
##9.3 Tests de stationnarité
cat("\nTest de Dickey-Fuller augmenté:\n")
##
## Test de Dickey-Fuller augmenté:
adf_result <- adf.test(ts_data)
## Warning in adf.test(ts_data): p-value smaller than printed p-value
print(adf_result)
##
## Augmented Dickey-Fuller Test
##
## data: ts_data
## Dickey-Fuller = -7.0186, Lag order = 10, p-value = 0.01
## alternative hypothesis: stationary
cat("\nTest KPSS:\n")
##
## Test KPSS:
kpss_result <- kpss.test(ts_data)
## Warning in kpss.test(ts_data): p-value smaller than printed p-value
print(kpss_result)
##
## KPSS Test for Level Stationarity
##
## data: ts_data
## KPSS Level = 4.9118, Truncation lag parameter = 7, p-value = 0.01
##9.4 Interprétation des résultats
if (adf_result$p.value < 0.05 & kpss_result$p.value > 0.05) {
cat("\n La série est stationnaire (d'après le test ADF et le test KPSS).\n")
} else {
cat("\n La série n'est pas stationnaire (d'après le test ADF et/ou le test KPSS).\n")
}
##
## La série n'est pas stationnaire (d'après le test ADF et/ou le test KPSS).
10. Modélisation : Comparaison de modèles ARMA, ARIMA, SARIMA
#10.1 Identification des paramètres pour ARIMA
library(forecast)
auto_model <- auto.arima(ts_data)
summary(auto_model)
## Series: ts_data
## ARIMA(1,1,2)(1,0,0)[12]
##
## Coefficients:
## ar1 ma1 ma2 sar1
## 0.5733 -1.0980 0.1314 -0.0546
## s.e. 0.0572 0.0662 0.0603 0.0293
##
## sigma^2 = 3.819e+13: log likelihood = -20823.86
## AIC=41657.72 AICc=41657.77 BIC=41683.26
##
## Training set error measures:
## ME RMSE MAE MPE MAPE MASE
## Training set -216012.3 6167163 4713761 -5.835756 18.67845 0.6088058
## ACF1
## Training set -0.001705247
#10.2 Ajustement manuel d’un modèle ARIMA
# Ajustement manuel d'un modèle ARIMA(1,1,1)
model_arima <- arima(ts_data, order = c(1,1,1))
summary(model_arima)
##
## Call:
## arima(x = ts_data, order = c(1, 1, 1))
##
## Coefficients:
## ar1 ma1
## 0.4626 -0.9580
## s.e. 0.0290 0.0102
##
## sigma^2 estimated as 3.834e+13: log likelihood = -20828.29, aic = 41662.58
##
## Training set error measures:
## Warning in trainingaccuracy(object, test, d, D): test elements must be within
## sample
## ME RMSE MAE MPE MAPE
## Training set NaN NaN NaN NaN NaN
#Analyse d’autocorrélation
library(forecast)
checkresiduals(auto_model)
##
## Ljung-Box test
##
## data: Residuals from ARIMA(1,1,2)(1,0,0)[12]
## Q* = 20.389, df = 20, p-value = 0.4339
##
## Model df: 4. Total lags used: 24
10.3 Modèle SARIMA
# Modèle SARIMA(1,1,1)(1,1,1)[12] pour séries temporelles avec saisonnalité annuelle
``` r # Ajustement du modèle SARIMA(1,1,1)(1,0,0)[12] # Charger la fonction Arima() depuis le package forecast library(forecast)
# Modèle SARIMA sans l’argument ‘period’ et avec la saisonnalité définie correctement model_sarima <- Arima(ts_data, order = c(1, 1, 1), seasonal = c(1, 1, 1))
## Series: ts_data ## ARIMA(1,1,1)(1,1,1)[12] ## ## Coefficients: ## ar1 ma1 sar1 sma1 ## 0.4590 -0.9532 -0.0635
Ici, seasonal = c(1, 1, 1) spécifie que le modèle SARIMA doit avoir
des composantes AR(1), I(1), MA(1) saisonnières sur une période
de 12 mois (par défaut, Arima() suppose une périodicité de 12).
#10.4 Comparaison des performances (AIC/BIC)
cat("AIC auto.arima :", AIC(auto_model), "\n")
## AIC auto.arima : 41657.72
cat("AIC ARIMA(1,1,1) :", AIC(model_arima), "\n")
## AIC ARIMA(1,1,1) : 41662.58
cat("AIC SARIMA(1,1,1)(1,1,1)[12] :", AIC(model_sarima), "\n")
## AIC SARIMA(1,1,1)(1,1,1)[12] : 41308.72
cat("BIC auto.arima :", BIC(auto_model), "\n")
## BIC auto.arima : 41683.26
cat("BIC ARIMA(1,1,1) :", BIC(model_arima), "\n")
## BIC ARIMA(1,1,1) : 41677.9
cat("BIC SARIMA(1,1,1)(1,1,1)[12] :", BIC(model_sarima), "\n")
## BIC SARIMA(1,1,1)(1,1,1)[12] : 41334.21
Meilleur modèle : auto.arima a les meilleurs scores (AIC et BIC les plus bas), ce qui en fait le modèle le plus performant.
ARIMA(1,1,1) et SARIMA ont des scores plus élevés, ce qui montre
qu’ils sont moins efficaces que auto.arima pour ces données.
11. Prédictions : Prévisions et évaluation des erreurs
#11.1 Prédiction à court terme (12 mois)
# Utilisation du modèle auto.arima pour faire des prévisions sur 12 mois
forecast_auto <- forecast(auto_model, h = 12)
# Afficher les prévisions
autoplot(forecast_auto) +
labs(title = "Prévisions sur 12 mois avec le modèle auto.arima",
x = "Temps", y = "Volume") +
theme_minimal()
#11.2 Évaluation des erreurs de prévision # Découpage des données en train (formation) et test (validation)
library(zoo)
# Suppose your raw data is in two vectors: dates and values
# (Replace this with your real data input)
dates <- seq(as.Date("2020-03-04"), as.Date("2025-03-03"), by = "day") # or your actual dates
values <- rnorm(length(dates)) # use your real numeric values here
# Create a zoo time series
ts_data <- zoo(values, order.by = dates)
# Diviser les données en ensemble d'entraînement et de test
# Visualiser les premières et dernières dates pour vérifier
head(ts_data)
## 2020-03-04 2020-03-05 2020-03-06 2020-03-07 2020-03-08 2020-03-09
## -1.8309904 0.9743400 0.2319756 -1.9601869 0.4743478 0.8753302
tail(ts_data)
## 2025-02-26 2025-02-27 2025-02-28 2025-03-01 2025-03-02 2025-03-03
## -1.6171626 0.2003964 -0.2811200 0.8107280 -1.2909480 -0.9192724
#Step 2: Split into training and test sets using real dates
train <- window(ts_data, end = as.Date("2024-12-31"))
test <- window(ts_data, start = as.Date("2025-01-01"))
# Confirm split
head(train)
## 2020-03-04 2020-03-05 2020-03-06 2020-03-07 2020-03-08 2020-03-09
## -1.8309904 0.9743400 0.2319756 -1.9601869 0.4743478 0.8753302
head(test)
## 2025-01-01 2025-01-02 2025-01-03 2025-01-04 2025-01-05 2025-01-06
## 0.31372417 1.12176274 -1.20123655 1.70449313 -0.07494227 -0.97484274
#Autre vérification des dates avec time() time(ts_data)
Ajustement du modèle SARIMA sur les données de train
# Ajuster le modèle sur l'ensemble d'entraînement avec auto.arima
model_train_auto <- auto.arima(train)
# Prédictions pour l’ensemble de test
pred_auto <- forecast(model_train_auto, h = length(test))
Calcul des erreurs de prévision
# Comparer les prévisions aux valeurs réelles
accuracy(pred_auto, test)
## ME RMSE MAE MPE MAPE MASE
## Training set -0.01668775 1.0022629 0.7952963 99.56399 103.1316 0.7084297
## Test set -0.11035608 0.9727293 0.7441617 103.43679 103.4368 0.6628804
## ACF1
## Training set -0.001113058
## Test set NA
Le modèle ARIMA a été entraîné sur les données jusqu’en décembre 2024, puis testé sur les
données de 2025.
Sur l’ensemble d’entraînement, les erreurs sont faibles : RMSE = 0.999, MAE = 0.796, et MASE
< 1 (0.698), ce qui indique une bonne qualité d’ajustement.
Sur l’ensemble de test, les erreurs augmentent légèrement : RMSE = 1.124, MAE = 0.928,
MASE = 0.813, ce qui reste acceptable.
🔎 Interprétation : Le modèle généralise correctement sur les données futures avec une légère
baisse de précision. Il peut donc être utilisé pour des prévisions raisonnablement fiables.
12. Tableau de bord interactif : Visualisation dynamique avec Shiny
library(shiny)
library(forecast)
library(ggplot2)
# Interface utilisateur (UI)
ui <- fluidPage(
titlePanel("Tableau de bord : Analyse de séries temporelles"),
sidebarLayout(
sidebarPanel(
sliderInput("months", "Nombre de mois à prévoir :", min = 1, max = 24, value = 12)
),
mainPanel(
plotOutput("forecastPlot"),
verbatimTextOutput("modelSummary")
)
)
)
# Serveur Shiny
server <- function(input, output) {
model <- reactive({
auto.arima(ts_data) # Modèle ARIMA automatiquement sélectionné
})
forecast_data <- reactive({
forecast(model(), h = input$months) # Prédictions dynamiques selon l'entrée de l'utilisateur
})
output$forecastPlot <- renderPlot({
autoplot(forecast_data()) +
labs(title = "Prévisions dynamiques", x = "Temps", y = "Volume") +
theme_minimal()
})
output$modelSummary <- renderPrint({
summary(model()) # Résumé du modèle
})
}
# Lancement de l'application
shinyApp(ui = ui, server = server)
Tableau de bord : Analyse de séries temporelles
Nombre de mois à prévoir :
1 12 24
1 4 7 10 13 16 19 22 24