"""Outils de moyennage saisonnier/mensuel et de profils horaires.""" from __future__ import annotations from typing import Sequence import pandas as pd from meteo.season import SEASON_LABELS from .core import MONTH_ORDER, _ensure_datetime_index, _infer_time_step __all__ = ['compute_monthly_climatology', 'compute_monthly_means', 'compute_seasonal_hourly_profile', 'compute_monthly_daylight_hours'] def compute_monthly_climatology( df: pd.DataFrame, *, columns: Sequence[str], ) -> pd.DataFrame: """ Moyenne par mois (1–12) pour les colonnes fournies. """ _ensure_datetime_index(df) missing = [col for col in columns if col not in df.columns] if missing: raise KeyError(f"Colonnes absentes : {missing}") grouped = df[list(columns)].groupby(df.index.month).mean() grouped = grouped.reindex(MONTH_ORDER) grouped.index.name = "month" return grouped def compute_monthly_means( df: pd.DataFrame, *, columns: Sequence[str], ) -> pd.DataFrame: """ Moyennes calendaire par mois (indexé sur la fin de mois). """ _ensure_datetime_index(df) missing = [col for col in columns if col not in df.columns] if missing: raise KeyError(f"Colonnes absentes : {missing}") monthly = df[list(columns)].resample("1ME").mean() return monthly.dropna(how="all") def compute_seasonal_hourly_profile( df: pd.DataFrame, *, value_column: str, season_column: str = "season", ) -> pd.DataFrame: """ Retourne une matrice (heures x saisons) contenant la moyenne d'une variable. """ _ensure_datetime_index(df) for col in (value_column, season_column): if col not in df.columns: raise KeyError(f"Colonne absente : {col}") subset = df[[value_column, season_column]].dropna() if subset.empty: return pd.DataFrame(index=range(24)) grouped = subset.groupby([season_column, subset.index.hour])[value_column].mean() pivot = grouped.unstack(season_column) pivot = pivot.reindex(index=range(24)) order = [season for season in SEASON_LABELS if season in pivot.columns] if order: pivot = pivot[order] pivot.index.name = "hour" return pivot def compute_monthly_daylight_hours( df: pd.DataFrame, *, illuminance_column: str = "illuminance", threshold_lux: float = 1000.0, ) -> pd.Series: """ Calcule la durée moyenne de luminosité (> threshold_lux) par mois (en heures par jour). """ _ensure_datetime_index(df) if illuminance_column not in df.columns: raise KeyError(f"Colonne absente : {illuminance_column}") subset = df[[illuminance_column]].dropna() if subset.empty: return pd.Series(dtype=float) time_step = _infer_time_step(subset.index) hours_per_step = time_step.total_seconds() / 3600.0 daylight_flag = (subset[illuminance_column] >= threshold_lux).astype(float) daylight_hours = daylight_flag * hours_per_step daily_hours = daylight_hours.resample("1D").sum() monthly_avg = daily_hours.resample("1ME").mean() return monthly_avg.dropna()