Spaces:
Sleeping
Sleeping
File size: 4,389 Bytes
dbbcfdf f50ea8d 54e9f72 accb9cc 54e9f72 678ebbd 54e9f72 5dc672c 54e9f72 678ebbd accb9cc 678ebbd 5dc672c 678ebbd 54e9f72 accb9cc 678ebbd 54e9f72 accb9cc 7170014 8fd92f9 54e9f72 7170014 54e9f72 678ebbd 54e9f72 678ebbd 54e9f72 d09b7ea accb9cc 7170014 accb9cc 2db5e22 54e9f72 2db5e22 accb9cc 5dc672c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 | import pandas as pd
import numpy as np
from config import CITIES_COORDS
def apply_feature_engineering(df_input):
df = df_input.copy()
# 1. Nettoyage des types (Évite l'erreur TypeError str vs int)
df['time'] = pd.to_datetime(df['time'])
numeric_cols = [
'temperature_2m_max', 'temperature_2m_min', 'temperature_2m_mean',
'precipitation_sum', 'wind_speed_10m_max', 'wind_gusts_10m_max',
'shortwave_radiation_sum', 'et0_fao_evapotranspiration', 'sunshine_duration', 'daylight_duration'
]
for col in numeric_cols:
if col in df.columns:
df[col] = pd.to_numeric(df[col], errors='coerce').fillna(0)
# 2. Tri impératif pour les calculs de séries temporelles
df = df.sort_values(['city', 'time']).reset_index(drop=True)
# 3. Calendrier
df['mois'] = df['time'].dt.month
df['annee'] = df['time'].dt.year
df['quarter'] = df['time'].dt.quarter
df['day_of_year'] = df['time'].dt.dayofyear
df['month_sin'] = np.sin(2 * np.pi * df['mois'] / 12)
df['month_cos'] = np.cos(2 * np.pi * df['mois'] / 12)
df['day_sin'] = np.sin(2 * np.pi * df['day_of_year'] / 365)
df['day_cos'] = np.cos(2 * np.pi * df['day_of_year'] / 365)
# 4. Physique et Indices
df['amplitude_thermique'] = df['temperature_2m_max'] - df['temperature_2m_min']
df['ecart_ressenti'] = df['apparent_temperature_mean'] - df['temperature_2m_mean']
df['bilan_hydrique'] = df['precipitation_sum'] - df['et0_fao_evapotranspiration']
df['sunshine_ratio'] = df['sunshine_duration'] / (df['daylight_duration'] + 1e-6)
df['gust_ratio'] = df['wind_gusts_10m_max'] / (df['wind_speed_10m_max'] + 1e-6)
df['heat_stress'] = df['temperature_2m_mean'] * df['et0_fao_evapotranspiration']
df['temp_per_radiation'] = df['temperature_2m_mean'] / (df['shortwave_radiation_sum'] + 1e-6)
df['is_dry_season'] = df['mois'].isin([11, 12, 1, 2, 3]).astype(int)
df['is_weekend'] = df['time'].dt.dayofweek.isin([5, 6]).astype(int)
df['is_no_rain'] = (df['precipitation_sum'] < 0.1).astype(int)
df['is_no_wind'] = (df['wind_speed_10m_max'] < 5).astype(int)
df['stagnation_index'] = ((df['wind_speed_10m_max'] < 15) & (df['precipitation_sum'] == 0)).astype(int)
df['is_hot_day'] = (df['temperature_2m_max'] >= 35).astype(int)
df['is_heavy_rain'] = (df['precipitation_sum'] >= 20).astype(int)
# 5. Groupement par ville pour les Lags et Rolling
# On utilise groupby().transform pour garder la taille originale du DF
grouped = df.groupby('city')
for lag in [1, 3, 7]:
df[f'temp_lag{lag}'] = grouped['temperature_2m_mean'].shift(lag)
df[f'wind_lag{lag}'] = grouped['wind_speed_10m_max'].shift(lag)
df[f'precip_lag{lag}'] = grouped['precipitation_sum'].shift(lag)
df[f'wind_dir_lag{lag}'] = grouped['wind_direction_10m_dominant'].shift(lag)
df[f'sunshine_lag{lag}'] = grouped['sunshine_duration'].shift(lag)
df['temp_roll7'] = grouped['temperature_2m_mean'].transform(lambda x: x.rolling(7, min_periods=1).mean())
df['precip_roll7'] = grouped['precipitation_sum'].transform(lambda x: x.rolling(7, min_periods=1).mean())
df['wind_roll7'] = grouped['wind_speed_10m_max'].transform(lambda x: x.rolling(7, min_periods=1).mean())
df['temp_roll30'] = grouped['temperature_2m_mean'].transform(lambda x: x.rolling(30, min_periods=1).mean())
df['temp_anomaly'] = df['temperature_2m_mean'] - df['temp_roll30']
df['precip_cumul7'] = grouped['precipitation_sum'].transform(lambda x: x.rolling(7, min_periods=1).sum())
df['precip_cumul3'] = grouped['precipitation_sum'].transform(lambda x: x.rolling(3, min_periods=1).sum())
def get_region_name(city):
return CITIES_COORDS.get(city, {}).get('region', 'Littoral')
df['region'] = df['city'].apply(get_region_name)
def categorize_weather(code):
if code == 0: return 'Ciel dégagé'
elif code in [1, 2]: return 'Nuageux'
elif code == 3: return 'Couvert'
else: return 'Pluie/Bruine'
df['weather_categorie'] = df['weather_code'].apply(categorize_weather)
df['weather_encoded'] = df['weather_code'].astype(float)
cols_to_fix = [c for c in df.columns if 'lag' in c or 'roll' in c]
for col in cols_to_fix:
df[col] = df.groupby('city')[col].ffill().bfill()
return df.fillna(0) |