7.2 Rétropropagation
Objectifs d'apprentissage
À la fin de cette section, vous devriez être en mesure de :
- 7.2.1 Discuter de l'objectif de l'ajustement des poids et des biais pour réduire la perte/l'erreur dans un réseau de neurones.
- 7.2.2 Utiliser la rétropropagation statique pour entraîner un réseau de neurones.
- 7.2.3 Définir les réseaux de neurones récurrents et discuter de leurs avantages et inconvénients.
Dans la section précédente, nous avons abordé le perceptron monocouche. L'entraînement du perceptron est simple car il nécessite seulement d'ajuster un ensemble de poids et de biais qui influent directement sur la sortie. En revanche, les réseaux de neurones comportant plus d'une couche, comme les perceptrons multicouches (MLP), doivent être entraînés au moyen de méthodes capables de modifier également les poids et les biais dans les couches cachées.
La rétropropagation (backpropagation) est un algorithme utilisé pour entraîner des réseaux de neurones en déterminant la manière dont les erreurs dépendent des variations des poids et des biais de tous les neurones, en partant de la couche de sortie et en remontant à travers les couches, actualisant récursivement les paramètres en fonction de la variation de l'erreur dans chaque couche. Dans cette section, nous examinerons comment les réseaux de neurones ajustent leurs poids et leurs biais pour minimiser l'erreur (ou perte), améliorant ainsi leur capacité à formuler des prédictions exactes. Fondamentalement, la rétropropagation constitue un vaste problème d'optimisation. Dans ce manuel, nous nous concentrons sur les principes intuitifs de ce problème d'optimisation plutôt que d'entrer dans une analyse approfondie des méthodes et de la théorie requises pour exécuter les étapes d'optimisation de la rétropropagation.
Pour aller plus loin
Rétropropagation
Un traitement complet de la rétropropagation nécessite d'être familiarisé, entre autres, avec les opérations matricielles, le calcul différentiel et intégral ainsi que l'analyse numérique. De tels sujets dépassent largement le cadre de cet ouvrage, mais il existe de nombreuses ressources en ligne plus détaillées, telles que Neural Networks and Deep Learning de Michael Nielsen (2019) et What Is Backpropagation Really Doing? de 3Blue1Brown.
Rétropropagation statique
La rétropropagation est un algorithme d'apprentissage supervisé, ce qui signifie qu'il s'entraîne sur des données préalablement étiquetées (voir Qu'est-ce que l'apprentissage automatique ? pour en savoir plus sur l'apprentissage supervisé en général). L'objectif est d'ajuster itérativement les poids des connexions entre les neurones du réseau et les biais associés à chaque neurone afin de minimiser l'écart entre la sortie prédite et les valeurs cibles réelles. Le terme rétropropagation statique (static backpropagation) fait référence à l'ajustement des paramètres (poids et biais) uniquement, par opposition à la rétropropagation dynamique (dynamic backpropagation), qui peut également modifier la structure sous-jacente (neurones, couches, connexions, etc.).
Voici un aperçu général de l'algorithme de rétropropagation statique :
- Passe avant (forward pass). Durant la passe avant, les données d'entrée sont propagées à travers le réseau couche par couche, en utilisant les valeurs actuelles des poids et des biais ainsi que la fonction d'activation choisie, . Si le vecteur d'entrée est noté , et les couches cachées par , , etc., jusqu'à atteindre la couche de sortie, , alors chaque vecteur est obtenu à partir du précédent au moyen d'une formule de la forme . (Remarque : cette formule dissimule un volume important de calculs numériques complexes. Les valeurs de et sont propres à chaque couche et renferment donc les données de poids et de biais de l'ensemble des neurones de cette couche. En réalité, n'est plus seulement un simple vecteur dans ce contexte, mais une matrice, que l'on peut considérer comme un tableau de nombres. Enfin, la fonction d'activation est appliquée à toutes les composantes du vecteur d'entrée, produisant une sortie vectorielle. Ces détails ne sont toutefois pas indispensables à la compréhension fondamentale du processus.)
- Calcul de l'erreur. Dès que le réseau génère une sortie, l'erreur entre la sortie prédite et la valeur cible réelle est calculée. L'erreur peut être mesurée de multiples façons. La fonction employée pour mesurer l'erreur dans un réseau de neurones est appelée une fonction de perte ou de coût (loss or cost function).
- Passe arrière (rétropropagation). L'erreur à chaque couche est propagée récursivement vers l'arrière à travers le réseau.
- Actualisation des paramètres. Les poids et les biais du réseau sont actualisés de manière à réduire l'erreur, généralement à l'aide d'un algorithme d'optimisation tel que la descente de gradient (que nous aborderons plus loin).
- Répétition. Les étapes sont répétées sur les données d'entraînement jusqu'à atteindre un niveau d'exactitude suffisant.
Erreur et perte
Error generally refers to the difference between the predicted output of the neural network and the actual target values for a single data point. It is a quantitative measure of the mistakes made by the network in its predictions. The loss function is a mathematical function that takes the predicted output and the actual target values as inputs and outputs a single value representing the error. Learning is essentially minimizing the loss function over all training data. Suppose that the neural network outputs and the target output is . Common loss functions that would measure the error between and include:
- Erreur quadratique moyenne (MSE) : . La formule de la MSE (introduite dans Entraîner et tester un modèle) est importante en raison de son lien avec le concept de variance en statistique. C'est une fonction de perte fréquemment utilisée dans les tâches de régression, où l'objectif consiste à prédire des valeurs continues.
- Perte d'entropie croisée binaire (binary cross entropy loss) : . Cette fonction de perte est couramment utilisée pour les tâches de classification binaire, c'est-à-dire lorsque la sortie vaut soit 0, soit 1. (Remarque : le signe moins devant la formule sert à rendre la valeur globale positive, car les valeurs des logarithmes sont généralement négatives. Le terme entropie est lié aux mesures de l'information définies dans Arbres de décision.)
- Perte charnière (hinge loss) : . Cette fonction est également couramment utile en classification binaire.
- Entropie croisée catégorielle creuse (sparse categorical cross entropy) : une généralisation de l'entropie croisée binaire, particulièrement utile lorsque les étiquettes cibles sont des entiers.
La perte moyenne est calculée comme la moyenne de la perte sur l'ensemble des points de données. Plus la perte moyenne est proche de zéro, plus l'erreur de prédiction est faible. Le choix de la fonction de perte dépend de la tâche spécifique, de la nature des entrées et des sorties ainsi que de nombreux autres facteurs, qui seront abordés plus en détail dans Introduction à l'apprentissage profond.
Exemple 7.3
Problème
Les sorties d'un réseau de neurones sur deux points de données sont présentées dans le Tableau 7.1 :
| Point de données | Prédit | Réel (Cible) |
|---|---|---|
| 1 | ||
| 2 |
Calculez la perte moyenne à l'aide des fonctions de perte suivantes.
- MSE
- Perte d'entropie croisée binaire
- Perte charnière
Solution
Ici, le nombre de termes est .
- MSE
Point de données 1 :
Point de données 2 :
- Perte d'entropie croisée binaire
Raccourci : Si , le premier terme est nul, , et le second terme se réduit à . Si , le second terme est nul, , et le premier terme se réduit à .
Point de données 1 :
Point de données 2 :
Perte moyenne : - Perte charnière
Calculez d'abord les valeurs de . Ensuite, si l'une d'elles est négative, utilisez plutôt 0 dans la somme.
Point de données 1 : . . . .
Point de données 2 : . . . .
Perte moyenne :
Remarque : le fait que chacune des trois fonctions de perte donne un résultat différent peut traduire la nature des erreurs par rapport à la performance du modèle, mais avec seulement deux points de données dans cet exemple, il n'est pas conseillé d'accorder trop d'importance à ces chiffres.
Descente de gradient et rétropropagation
L'objectif de l'entraînement d'un réseau de neurones étant de réduire la valeur de l'erreur ou de la perte, nous devons essentiellement résoudre un (très vaste) problème d'optimisation. Supposons que vous entraîniez un réseau de neurones. Considérez l'ensemble des poids et des biais — qui peuvent se compter par milliers, par millions, voire davantage ! — comme les paramètres actuels du réseau susceptibles d'être modifiés pour améliorer le modèle. Lors d'une passe avant avec un vecteur d'entrée arbitraire , la sortie est obtenue et comparée à la sortie réelle au moyen d'une fonction de perte, . Comment exploiter cette information pour modifier les paramètres (poids et biais) afin que, lors de la passe suivante avec le même vecteur d'entrée , la sortie constitue une représentation plus exacte de la sortie réelle , au sens où la valeur de diminue ? La clé consiste à appréhender l'ensemble du réseau de neurones et le calcul de la perte comme une fonction des poids et des biais , puis à utiliser des techniques comme la descente de gradient (que nous aborderons brièvement dans la section suivante) pour en trouver la valeur minimale. Ici, et sont en majuscules car ils représentent la multiplicité des poids et des biais à travers tout le réseau, et non ceux d'un seul neurone ou d'une seule couche. La Figure 7.7 présente un schéma illustrant la fonction en tant que processus composite.
As a very simple example, suppose that a neural network has only one neuron with weight and bias . Input is fed into the neuron, the weight and bias are applied to , and then an activation function is applied to the result to produce an output . We’ll use the sigmoid, as activation function for simplicity. Now, the result, , is compared to the true value , using a cost function, which for this example will be MSE. The composite function looks like this:
S'il y avait davantage de neurones, de poids et de biais, la formule serait beaucoup plus complexe, car il faudrait prendre en compte un nombre bien supérieur de variables et de paramètres, mais le concept fondamental reste identique. Nous voulons trouver les valeurs de et de qui minimisent la valeur de . Cela exige de nombreux cycles successifs d'ajustement des poids et des biais en se basant sur les valeurs de la fonction de perte. Chaque cycle d'entraînement complet est appelé une époque (epoch).
Now suppose that and . Consider a single point from the set of training data—for example, . The neural network computes a prediction, , as follows:
La perte par rapport à la sortie réelle donnée est :
Thus, we have the value , which indicates that there is some nonzero amount of loss on the prediction just made, and so the values of and should be adjusted. Instead of trying to adjust and individually, let’s find the direction from the point (0.5, 0.25) that would result in the fastest decrease of the error . If we label the direction of steepest decrease , then we could move from the point (0.5, 0.25) to a new point, , where is a small number that affects the learning rate of the neural network. This is the main idea behind gradient descent. In our example, we could find the direction of steepest descent by simply looking at how the surface is slanted near the point (0.5, 0.25). Figure 7.8 indicates the best direction with an arrow. (However, in practice, there will be no way to visualize the graph of loss with respect to weights and biases () because the points exist in very high-dimensional spaces. The details of gradient descent and how it is used in neural networks falls outside the scope of this textbook. (See this IBM article for a great introduction to this topic.)
Un dernier point à souligner est que la descente de gradient ne fonctionne que lorsque la fonction F est différentiable, ce qui signifie que la courbe de ne comporte ni angles vifs, ni points de rebroussement, ni points de discontinuité. Dans la mesure où est une composition de nombreuses fonctions composantes, chaque composante doit être différentiable. Les fonctions d'activation telles que la fonction en escalier, ReLU et LReLU ne peuvent pas être employées directement avec la descente de gradient. D'autres méthodes sont toutefois disponibles pour rétropropager et entraîner ce type de réseaux. Une autre solution consiste à approximer les fonctions d'activation non lisses par des versions régulières — par exemple, sigmoïde ou tanh à la place de la fonction en escalier, ou softplus à la place de ReLU.
Entraîner un réseau de neurones par rétropropagation en Python avec TensorFlow
La bibliothèque Python TensorFlow, développée à l'origine par l'équipe Google Brain en 2015, permet de concevoir un réseau de neurones doté de la rétropropagation. (Un tenseur (tensor) est un tableau multidimensionnel, généralisant le concept de vecteur.)
Mettons en place un réseau de neurones et entraînons-le à reconnaître des chiffres manuscrits de la base de données MNIST. Ce jeu de données, nommé mnist_784, peut être chargé automatiquement au moyen de la commande fetch_openml. Les étiquettes cibles doivent être converties explicitement en nombres entiers. Les données sont ensuite scindées en ensembles d'entraînement (80 %) et de test (20 %). Les variables explicatives sont renormalisées à l'aide de StandardScaler. Le modèle de réseau de neurones est ensuite créé avec tf.keras.Sequential. L'architecture peut être très complexe, mais nous nous limiterons au cas le plus simple : une couche d'entrée comprenant exactement autant de neurones que de variables (784) et une couche de sortie de 10 neurones, un pour chaque chiffre. Ce modèle ne comprend aucune couche cachée. La commande tf.keras.layers.Dense crée la couche de sortie de 10 neurones entièrement connectée à la couche d'entrée de 784 neurones (la valeur de X_train_scaled.shape[1]). La fonction d'activation softmax est employée, mais d'autres fonctions telles que ReLU sont également envisageables. Le paramètre optimizer='adam' dans la fonction model.compile fait référence à l'algorithme Adaptive Moment Estimation, utilisé pour actualiser les poids et les biais du modèle durant l'apprentissage, dont les détails techniques dépassent le cadre de cet ouvrage.
Remarque : Ce code nécessite un certain temps d'exécution — jusqu'à 5 minutes ! Même sans couche cachée, la rétropropagation prend du temps. Lors de l'exécution, vous devriez observer des barres de progression pour chaque époque (non représentées dans la sortie Python de l'encadré ci-dessous).
Code Python
# import the libraries
import tensorflow as tf
from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
# Load MNIST Digits dataset
mnist = fetch_openml('mnist_784', version=1)
# Split the dataset into training and testing sets 80/20
X_train, X_test, y_train, y_test = train_test_split(mnist.data, mnist.target, test_size=0.2, random_state=42)
# Standardize features by removing the mean and scaling to unit variance
scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_test_scaled = scaler.transform(X_test)
# Cast the target variable as an integer (int32)
y_train = y_train.astype('int32')
y_test = y_test.astype('int32')
# Define the neural network architecture
model = tf.keras.Sequential([
tf.keras.layers.Dense(10, activation='softmax', input_shape=(X_train_scaled.shape[1],))
])
# Compile the model
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy'])
# Train the model
history = model.fit(X_train_scaled, y_train, epochs=10, batch_size=32, validation_split=0.2)
# Evaluate the model on test data
test_loss, test_accuracy = model.evaluate(X_test_scaled, y_test)
print("Test Loss:", test_loss)
print("Test Accuracy:", test_accuracy)
La sortie obtenue se présentera ainsi :
Test Loss: 0.4051963686943054
Test Accuracy: 0.9189285635948181
Réseaux de neurones récurrents
Imaginez que vous puissiez prédire les cours de la bourse ! Et si vous disposiez d'un modèle capable de prendre les cours des jours précédents d'une action pour en prévoir le cours de demain ? Vous pourriez alors maximiser vos profits en achetant au plus bas et en vendant au plus haut, en sachant parfaitement à quel moment se produiraient ces points d'inflexion. Compte tenu de la nature extrêmement imprévisible des marchés boursiers, il est peu probable qu'un modèle de prévision simple soit suffisant ; envisageons plutôt un réseau de neurones. On pourrait le concevoir de sorte que le vecteur d'entrée contienne les cours des 14 jours précédents et que la sortie y représente le cours prévu de l'action pour le jour suivant. Après un certain temps, vous décidez de modifier la structure du réseau pour qu'il prenne en compte 30 jours de données. Il vous faudrait alors tout recommencer, en réentraînant et en retestant le nouveau modèle à partir de zéro. En réalité, chaque fois que vous décideriez de modifier le nombre de valeurs d'entrée, vous devriez concevoir un nouveau modèle et recommencer les phases d'entraînement et de test. Il serait bien plus commode de disposer d'un modèle capable d'accepter des volumes variables de données en entrée. De plus, si le modèle s'entraîne d'abord sur 14 jours d'historique, il serait souhaitable que le réseau « se souvienne » de cet apprentissage, afin que lorsque des données supplémentaires sont disponibles (30 jours, 60 jours, un an, etc.), il puisse simplement affiner ses prédictions à partir de la base déjà acquise.
Cette souplesse est offerte par les réseaux de neurones récurrents (RNNs) (recurrent neural networks (RNNs)). Un RNN est un réseau de neurones qui intègre des boucles de rétroaction (feedback loops), c'est-à-dire des connexions internes d'un neurone vers lui-même ou formant des cycles entre plusieurs neurones. Concrètement, la sortie d'un neurone est réinjectée en entrée vers lui-même tout en étant transmise aux neurones de la couche suivante.
Dans le modèle le plus élémentaire, une boucle de rétroaction relie un neurone individuel à lui-même. La sortie du neurone est modulée par un poids de connexion (connecting weight) et le résultat est intégré à la somme constituant l'entrée de ce même neurone. Ainsi, lorsqu'un nouveau signal parvient au neurone, il reçoit en supplément le signal . Si le poids de connexion est positif, cela a pour effet général de rendre le neurone de plus en plus actif au fil du temps. En revanche, si le poids de connexion est négatif, il s'établit une boucle de rétroaction négative, qui atténue progressivement l'activité du neurone dans le temps. Les poids de connexion d'un RNN sont entraînés conjointement avec l'ensemble des poids et des biais du réseau à l'aide d'une variante de la rétropropagation appelée rétropropagation à travers le temps (ou BPTT). Voir la Figure 7.9 pour un schéma simple illustrant un modèle de RNN.
The RNN model’s feedback loops provide a simple memory, but how does it allow for different amounts of input values? The key is to feed in single (or small batches of) datapoints sequentially. For example, if represents the prices of a stock on day 1, 2, 3, up to , and the actual value of the stock on day is , the RNN will take in just one element (typically, the most recent data being used first) and adjust parameters based on the accuracy or loss of the prediction . On the next pass, it takes in and produces a new prediction . Keep in mind, the feedback loops allow the RNN to remember (in some capacity) how it performed on the first input, and so the prediction is based on the two data points, . Similarly, when is fed into the model on the third pass, the RNN will produce a new prediction that is based on the three data points, . Thus, the feedback loops of an RRN provide a mechanism for the input to consist of any number of sequential input data points. This makes RNNs especially useful for time series data (See Time Series and Forecasting for an introduction to time series.)
Dérouler un RNN
The effect of feedback loops may be visualized by “unrolling” the RNN. Consider the simplest case of a single feedback loop from one neuron to itself. The effect of the connecting weight is equivalent to connecting to a copy of the same RNN (with identical weights and biases). Of course, since the second copy of the RNN has the same feedback loop, it can be unrolled to a third, fourth, fifth copy, etc. An “unrolled” RNN with copies of the neural net has inputs. The effect of feeding the entire vector into the unrolled model is equivalent to feeding the data points sequentially into the RNN. Figure 7.10 shows how this works.
Problème de disparition ou d'explosion du gradient
Entraîner un RNN est plus complexe en raison de la grande sensibilité du modèle aux variations des poids de connexion. Au cours de la phase d'apprentissage, la descente de gradient et une variante de la rétropropagation (BPTT, comme indiqué précédemment) sont mises en œuvre pour ajuster l'ensemble des poids et des biais. Cependant, en raison des boucles de rétroaction propres aux RNN, les poids de connexion peuvent se multiplier de manière répétée jusqu'à atteindre des valeurs gigantesques. Dès lors, des algorithmes comme la descente de gradient perdent toute leur efficacité, car des poids élevés induisent des modifications proportionnellement excessives des paramètres, à l'opposé des ajustements infinitésimaux requis pour localiser des minima. C'est ce que l'on appelle le problème d'explosion du gradient (exploding gradient problem). À l'inverse, si les poids de connexion sont initialement trop faibles, l'entraînement peut les faire tendre très vite vers zéro, ce qui constitue le problème de disparition du gradient (vanishing gradient problem). Il est essentiel de prendre en compte ces deux écueils lors de l'utilisation de RNN, faute de quoi l'exactitude de votre modèle risque d'être sérieusement compromise.
Réseaux à mémoire court et long terme
Un réseau à mémoire court et long terme (LSTM) (long short-term memory (LSTM) network) est un type particulier de RNN conçu pour surmonter les problèmes d'explosion ou de disparition du gradient en intégrant des cellules de mémoire (memory cells) capables de capturer les dépendances à long terme bien mieux que de simples boucles de rétroaction. Introduits en 1997, les LSTM sont devenus incontournables dans de nombreuses applications, notamment le traitement du langage naturel, la reconnaissance vocale et la prévision de séries temporelles.
Les réseaux LSTM sont généralement plus stables et plus faciles à entraîner que les RNN classiques. Ils s'avèrent ainsi particulièrement indiqués pour la prévision de séries temporelles comportant des tendances à long terme et des comportements cycliques, ainsi que pour le traitement de données séquentielles d'apparence beaucoup plus imprévisible comme la modélisation du langage naturel, la traduction automatique et l'analyse de sentiments. Les RNN et les LSTM constituent un tremplin vers des modèles d'IA très sophistiqués, que nous examinerons dans la section suivante.
Les RNN en Python
Considérons le jeu de données MonthlyCoalConsumption.csv, que nous avons analysé au moyen des méthodes de séries temporelles de base dans Séries temporelles et prévisions. Ce jeu de données contient des observations s'étendant jusqu'à la fin de l'année 2022. Supposons que vous souhaitiez prévoir la consommation mensuelle de charbon pour chaque mois de l'année suivante à l'aide d'un réseau de neurones récurrent. Nous allons d'abord configurer un RNN simple en Python. La bibliothèque TensorFlow peut être utilisée pour concevoir un RNN. Nous emploierons pandas pour charger les données et numpy pour les structurer sous une forme plus exploitable (np.array) par le modèle. Le modèle RNN est défini à l'aide de la commande tf.keras.layers.SimpleRNN, où units précise le nombre de neurones dans la couche et activation='tanh' définit la fonction d'activation.
Code Python
import numpy as np
import pandas as pd
import tensorflow as tf
from sklearn.preprocessing import MinMaxScaler
# Load and preprocess the data
data = pd.read_csv('MonthlyCoalConsumption.csv')
values = np.array(data['Value'])
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_values = scaler.fit_transform(values.reshape(-1, 1))
# Prepare input sequences and target values
window_size = 12 # Number of months in each input sequence
X = []
y = []
for i in range(len(scaled_values) - window_size):
X.append(scaled_values[i:i+window_size])
y.append(scaled_values[i+window_size])
X = np.array(X)
y = np.array(y)
# Split data into training and testing sets
split = int(0.8 * len(X))
X_train, X_test = X[:split], X[split:]
y_train, y_test = y[:split], y[split:]
# Define the RNN architecture
model = tf.keras.Sequential([
tf.keras.layers.SimpleRNN(units=32, activation='tanh',
input_shape=(window_size, 1)),
tf.keras.layers.Dense(1)
])
# Compile the model
model.compile(optimizer='adam', loss='mean_squared_error')
# Train the model
model.fit(X_train, y_train, epochs=50, batch_size=16)
# Evaluate the model
loss = model.evaluate(X_test, y_test)
print("Test Loss:", loss)
La sortie obtenue se présentera ainsi :
Test Loss: 0.018054470419883728
La perte sur les données de test étant extrêmement faible, nous pouvons nous attendre à ce que le modèle soit très précis. Ensuite, le modèle peut être utilisé pour prédire les valeurs inconnues des 12 prochains mois. Remarque : les données d'origine ayant été mises à l'échelle, les prédictions fournies par le RNN doivent être reconverties en données non normalisées grâce à la commande scaler.inverse_transform.
Code Python
# Predict future values
future_months = 12
last_window = scaled_values[-window_size:].reshape(1, window_size, 1)
predicted_values = []
for _ in range(future_months):
prediction = model.predict(last_window)
predicted_values.append(prediction[0, 0])
last_window = np.append(last_window[:, 1:, :], prediction.reshape(1, 1, 1), axis=1)
# Inverse transform the predicted births to get actual values
predicted_values = scaler.inverse_transform(np.array(predicted_values).reshape(-1, 1))
print("Predicted Values for the Next 12 Months:\n", predicted_values.flatten())
La sortie obtenue se présentera ainsi :
Predicted Values for the Next 12 Months:
[49227.05 49190.258 41204.16 30520.389 29591.129 34516.586 42183.016
38737.39 32026.324 23482.027 23381.914 30206.467]
Enfin, voici le tracé superposant les données d'origine et les valeurs prédites. Remarque : de nombreuses lignes de code sont consacrées à la mise en forme des données et aux étiquettes des axes avant de tracer le graphique. C'est malheureusement le propre de ce type de visualisation. Le détail précis de chaque instruction ne fera pas l'objet d'une explication approfondie dans cet ouvrage.
Code Python
import matplotlib.pyplot as plt
from matplotlib.ticker import MaxNLocator ## for graph formatting
from matplotlib.ticker import FuncFormatter ## for formatting y-axis
# Function to format the Y-axis values
def y_format(value, tick_number):
return f'{value:,.0f}'
# Plot original time series data and predicted values
plt.figure(figsize=(10, 6))
plt.plot(data['Month'], data['Value'], label='Original Data', color='blue')
plt.plot(range(len(data['Value']), len(data['Value']) + future_months), predicted_values,
label='Predicted Values', color='red')
# Create a list for the months
pd_months = pd.date_range(start='2016-01-01', end='2023-07-01', freq='MS')
xticks_positions = range(0, len(pd_months), 6) # Positions to display ticks (e.g., every 12 months)
xticks_labels = [pd_months[pos].strftime('%Y-%m') for pos in xticks_positions] # Labels corresponding to positions
plt.xlabel('Month')
plt.ylabel('Value')
plt.title('Monthly Consumption of Coal from 2016 to 2022 and Predicted Values for 2023')
plt.legend()
plt.xticks(ticks=xticks_positions, labels=xticks_labels, rotation=45)
# Apply the formatter to the Y-axis
plt.gca().yaxis.set_major_formatter(FuncFormatter(y_format))
plt.show()
La sortie obtenue se présentera ainsi :