Spaces:
Sleeping
Sleeping
# Importation des bibliothèques nécessaires | |
import pandas as pd | |
import numpy as np | |
import glob | |
import matplotlib.pyplot as plt | |
import matplotlib as mpl | |
from sklearn.preprocessing import LabelEncoder, StandardScaler | |
from sklearn.metrics import mean_absolute_error, mean_squared_error | |
from sklearn.model_selection import TimeSeriesSplit | |
from xgboost import XGBRegressor | |
import joblib | |
import os | |
# Ajustement du paramètre agg.path.chunksize pour éviter l'OverflowError | |
mpl.rcParams['agg.path.chunksize'] = 10000 # Vous pouvez ajuster la valeur si nécessaire | |
# 1. Chargement des données | |
print("Chargement des données...") | |
parquet_files = glob.glob('FuelInFranceData/*.parquet') | |
if not parquet_files: | |
raise FileNotFoundError("Aucun fichier Parquet trouvé dans le répertoire spécifié.") | |
df_list = [] | |
for f in parquet_files: | |
print(f"Chargement du fichier {f}") | |
df_list.append(pd.read_parquet(f)) | |
df = pd.concat(df_list, ignore_index=True) | |
del df_list # Libération de la mémoire | |
print(f"Nombre total d'enregistrements: {len(df)}") | |
# 2. Prétraitement des données | |
print("Prétraitement des données...") | |
df['rate_date'] = pd.to_datetime(df['rate_date']) | |
df['brent_date'] = pd.to_datetime(df['brent_date']) | |
df = df.sort_values('rate_date') | |
df = df.dropna() | |
# Exclure les carburants E85 et GPLc | |
df = df[~df['fuel_name'].isin(['E85', 'GPLc'])] | |
# Sélection des colonnes pertinentes (inclure 'brent_date') | |
cols_to_use = ['station_id', 'commune', 'marque', 'departement', 'regioncode', | |
'coordlatitude', 'coordlongitude', 'fuel_name', 'price', | |
'rate_date', 'brent_rate_eur', 'brent_date'] | |
df = df[cols_to_use] | |
# Encodage des variables catégorielles | |
print("Encodage des variables catégorielles...") | |
label_encoders = {} | |
categorical_cols = ['station_id', 'commune', 'marque', 'departement', | |
'regioncode', 'fuel_name'] | |
for col in categorical_cols: | |
le = LabelEncoder() | |
df[col] = le.fit_transform(df[col].astype(str)) | |
label_encoders[col] = le | |
# 3. Nettoyage des valeurs aberrantes (outliers) | |
print("Nettoyage des valeurs aberrantes...") | |
# Suppression des outliers en utilisant l'IQR (Interquartile Range) | |
def remove_outliers_iqr(data, column): | |
Q1 = data[column].quantile(0.25) | |
Q3 = data[column].quantile(0.75) | |
IQR = Q3 - Q1 | |
lower_bound = Q1 - 1.5 * IQR | |
upper_bound = Q3 + 1.5 * IQR | |
data_clean = data[(data[column] >= lower_bound) & (data[column] <= upper_bound)] | |
return data_clean | |
df = remove_outliers_iqr(df, 'price') | |
# 4. Entraînement de modèles séparés pour chaque type de carburant avec validation croisée temporelle | |
print("Entraînement de modèles séparés pour chaque type de carburant avec validation croisée temporelle...") | |
fuel_types = df['fuel_name'].unique() | |
models = {} | |
scalers = {} | |
results = {} | |
for fuel in fuel_types: | |
fuel_name_decoded = label_encoders['fuel_name'].inverse_transform([fuel])[0] | |
print(f"\nTraitement du carburant: {fuel_name_decoded}") | |
df_fuel = df[df['fuel_name'] == fuel].copy() | |
# Ingénierie des caractéristiques | |
df_fuel['day_of_week'] = df_fuel['rate_date'].dt.dayofweek | |
df_fuel['month'] = df_fuel['rate_date'].dt.month | |
df_fuel['year'] = df_fuel['rate_date'].dt.year | |
# Création des variables de décalage (lags) pour le prix du Brent | |
for lag in [1, 3, 7, 15, 30]: | |
df_fuel[f'brent_rate_eur_lag_{lag}'] = df_fuel['brent_rate_eur'].shift(lag) | |
df_fuel = df_fuel.dropna() | |
# Variables features et target | |
X = df_fuel.drop(['price', 'rate_date', 'brent_date'], axis=1) | |
y = df_fuel['price'] | |
dates = df_fuel['rate_date'] | |
# Normalisation des données | |
scaler = StandardScaler() | |
X_scaled = scaler.fit_transform(X) | |
# Validation croisée temporelle | |
tscv = TimeSeriesSplit(n_splits=5) | |
y_tests = [] | |
y_preds = [] | |
dates_list = [] | |
for fold, (train_index, test_index) in enumerate(tscv.split(X_scaled)): | |
print(f" Fold {fold+1}/{tscv.get_n_splits()}") | |
X_train, X_test = X_scaled[train_index], X_scaled[test_index] | |
y_train, y_test = y.iloc[train_index], y.iloc[test_index] | |
dates_test = dates.iloc[test_index] | |
# Entraînement du modèle | |
model = XGBRegressor(objective='reg:squarederror', n_estimators=100, learning_rate=0.1) | |
model.fit(X_train, y_train) | |
# Prédiction sur l'ensemble de test | |
y_pred = model.predict(X_test) | |
# Stockage des résultats | |
y_tests.append(y_test) | |
y_preds.append(y_pred) | |
dates_list.append(dates_test) | |
# Concaténation des résultats | |
y_test_total = pd.concat(y_tests) | |
y_pred_total = np.concatenate(y_preds) | |
dates_total = pd.concat(dates_list) | |
# Évaluation du modèle | |
mae = mean_absolute_error(y_test_total, y_pred_total) | |
rmse = mean_squared_error(y_test_total, y_pred_total, squared=False) | |
print(f"Erreur Absolue Moyenne (MAE): {mae:.4f}") | |
print(f"Racine de l'Erreur Quadratique Moyenne (RMSE): {rmse:.4f}") | |
# Entraînement final sur l'ensemble des données pour la prévision future | |
model_final = XGBRegressor(objective='reg:squarederror', n_estimators=100, learning_rate=0.1) | |
model_final.fit(X_scaled, y) | |
# Sauvegarde du modèle final et du scaler | |
models[fuel] = model_final | |
scalers[fuel] = scaler | |
# Stockage des résultats pour l'analyse | |
results[fuel] = { | |
'y_test': y_test_total, | |
'y_pred': y_pred_total, | |
'dates': dates_total | |
} | |
# Sous-échantillonnage des données pour le tracé | |
downsample_rate = max(1, len(dates_total) // 1000) # Limiter à 1000 points | |
dates_sampled = dates_total.iloc[::downsample_rate] | |
y_test_sampled = y_test_total.iloc[::downsample_rate] | |
y_pred_sampled = y_pred_total[::downsample_rate] | |
# Tri des données pour le tracé | |
sorted_indices = np.argsort(dates_sampled) | |
dates_sampled = dates_sampled.iloc[sorted_indices] | |
y_test_sampled = y_test_sampled.iloc[sorted_indices] | |
y_pred_sampled = y_pred_sampled[sorted_indices] | |
# Graphique de validation (Prix prédit vs Prix réel) | |
plt.figure(figsize=(12, 6)) | |
plt.plot(dates_sampled, y_test_sampled, label='Prix Réel', marker='o', linestyle='None', markersize=4) | |
plt.plot(dates_sampled, y_pred_sampled, label='Prix Prédit', marker='x', linestyle='None', markersize=4) | |
plt.xlabel('Date') | |
plt.ylabel('Prix (€)') | |
plt.title(f"Comparaison du Prix Réel et Prédit pour le Carburant {fuel_name_decoded}") | |
plt.legend() | |
plt.tight_layout() | |
# Enregistrer le graphique | |
plt.savefig(f'validation_{fuel_name_decoded}.png') | |
plt.close() | |
# 5. Prévision pour les 3, 7, 15 et 30 prochains jours pour chaque carburant | |
print("\nPrévision pour les prochains jours pour chaque carburant...") | |
for fuel in fuel_types: | |
fuel_name_decoded = label_encoders['fuel_name'].inverse_transform([fuel])[0] | |
print(f"\nPrévisions pour le carburant: {fuel_name_decoded}") | |
df_fuel = df[df['fuel_name'] == fuel] | |
last_known_data = df_fuel.iloc[-1] | |
model = models[fuel] | |
scaler = scalers[fuel] | |
def forecast_prices(model, last_known_data, scaler, horizons=[3, 7, 15, 30]): | |
forecasts = {} | |
for horizon in horizons: | |
future_date = last_known_data['rate_date'] + pd.Timedelta(days=horizon) | |
input_data = last_known_data.to_frame().T.copy() | |
input_data['rate_date'] = future_date | |
input_data['day_of_week'] = future_date.dayofweek | |
input_data['month'] = future_date.month | |
input_data['year'] = future_date.year | |
# Mise à jour des variables de décalage du Brent | |
for lag in [1, 3, 7, 15, 30]: | |
input_data[f'brent_rate_eur_lag_{lag}'] = last_known_data['brent_rate_eur'] | |
input_data = input_data.dropna(axis=1, how='all') | |
# Préparation des données pour la prédiction | |
input_features = input_data.drop(['price', 'rate_date', 'brent_date'], axis=1) | |
input_features_scaled = scaler.transform(input_features) | |
predicted_price = model.predict(input_features_scaled) | |
forecasts[horizon] = predicted_price[0] | |
return forecasts | |
# Prévision des prix | |
forecasts = forecast_prices(model, last_known_data, scaler) | |
for horizon, price in forecasts.items(): | |
print(f"Dans {horizon} jours: {price:.4f} €") | |
# 6. Sauvegarde des modèles et des scalers pour une utilisation future | |
print("\nSauvegarde des modèles et des scalers...") | |
for fuel in fuel_types: | |
fuel_name_decoded = label_encoders['fuel_name'].inverse_transform([fuel])[0] | |
joblib.dump(models[fuel], f'fuel_price_model_{fuel_name_decoded}.pkl') | |
joblib.dump(scalers[fuel], f'scaler_{fuel_name_decoded}.pkl') | |
print("Script terminé avec succès.") |