Spaces:
Running
Running
File size: 6,239 Bytes
0ab0788 | 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 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | import numpy as np
import polars as pl
from scipy.special import gamma
# --- Quantile GEV ---
# Soit :
# μ(t) = μ₀ + μ₁ × t # localisation dépendante du temps
# σ(t) = σ₀ + σ₁ × t # échelle dépendante du temps
# ξ = constante # forme
# T = période de retour (années)
# p = 1 − 1 / T # probabilité non-excédée associée
# Avec t : année (ou covariable normalisée dans l'intervalle [0; 1]
# t = (annee - min_year) / (max_year - min_year) = (annee - min_year) / delta_year
# Une unité de t (normalisée) = Δa années (max_year - min_year)
# En notant Δa = max_year - min_year et a = annee, on a :
# t = (a − aₘᵢₙ) / Δa ⇒ a = aₘᵢₙ + t ⋅ Δa
# La quantile notée qᵀ(t) (précipitation pour une période de retour T à l’année t) s’écrit :
# qᵀ(t) = μ(t) + [σ(t) / ξ] × [ (−log(1 − p))^(−ξ) − 1 ]
# qᵀ(t) = (μ₀ + μ₁ × t) + [(σ₀ + σ₁ × t) / ξ] × [ (−log(1 − (1/T)))^(−ξ) − 1 ]
# Soit : z_T = [ -log(1 - 1/T) ]^(−ξ) − 1 ← constante pour un T donné
# Donc : qᵀ(t) = μ₀ + μ₁·t + [(σ₀ + σ₁·t) / ξ] · z_T
# Ou : qᵀ(t) = μ(t) + [σ(t) / ξ] · z_T
# En dérivant qᵀ par rapport à t on a :
# dqᵀ/dt = μ₁ + σ₁ / ξ · z_T
# On rappelle : a = aₘᵢₙ + t ⋅ Δa
# Donc : dt/da = 1 / Δa
# Alors dqᵀ/da = dqᵀ/dt · dt/da = μ₁ + σ₁ / ξ · z_T · 1 / Δa
# LA VARIATION PAR AN de qᵀ :
# dqᵀ/da = 1 / Δa · (μ₁ + σ₁ / ξ · z_T)
# DONC PAR 10 ANS :
# Δqᵀ₁₀ₐₙₛ = (10 / Δa) ⋅ (μ₁ + (σ₁ / ξ) ⋅ zᵀ)
def safe_compute_return_df(df: pl.DataFrame) -> pl.DataFrame:
REQUIRED_GEV_COLS = ["mu0", "mu1", "sigma0", "sigma1", "xi"]
for col in REQUIRED_GEV_COLS:
if col not in df.columns:
df = df.with_columns(pl.lit(0.0).alias(col))
df = df.with_columns([
pl.col(col).fill_null(0.0).fill_nan(0.0) for col in REQUIRED_GEV_COLS
])
return df
def compute_return_levels_ns(params: dict, T: np.ndarray, t_norm: float) -> np.ndarray:
"""
Calcule les niveaux de retour selon le modèle NS-GEV fourni.
- params : dictionnaire des paramètres GEV d'un point
- T : périodes de retour (en années)
- t_norm : covariable temporelle normalisée (ex : 0 pour année moyenne)
"""
mu = params.get("mu0", 0) + params["mu1"] * t_norm if "mu1" in params else params.get("mu0", 0) # μ(t)
sigma = params.get("sigma0", 0) + params["sigma1"] * t_norm if "sigma1" in params else params.get("sigma0", 0) # σ(t)
xi = params.get("xi", 0) # xi contant
if xi != 0:
qT = mu + (sigma / xi) * ((-np.log(1 - 1 / T))**(-xi) - 1)
else:
qT = mu - sigma * np.log(-np.log(1 - 1/T))
return qT
def delta_qT_X_years(mu1, sigma1, xi, T, year_range, par_X_annees):
"""
Calcule la variation décennale du quantile de retour qᵀ(t)
dans un modèle GEV non stationnaire avec t ∈ [0, 1].
La variation est ramenée à l’échelle des années civiles en tenant compte de la
durée totale du modèle (year_range = a_max - a_min).
Si un point de rupture est introduit year_range = a_max - a_rupture,
avec une Δqᵀ = 0 avant la rupture.
Δqᵀ = (par_X_annees / year_range) × (μ₁ + (σ₁ / ξ) × z_T)
avec :
- z_T = [ -log(1 - 1/T) ]^(-ξ) - 1 si ξ ≠ 0
= log(-log(1 - 1/T)) si ξ = 0 (Gumbel)
par_X_annees représente 10, 20, 30 ans dans Δ_10ans qᵀ
"""
try:
p = 1 - 1 / T
if xi == 0:
z_T = np.log(-np.log(p))
delta_q = (par_X_annees / year_range) * (mu1 + sigma1 * z_T)
else:
z_T = (-np.log(p))**(-xi) - 1
delta_q = (par_X_annees / year_range) * (mu1 + (sigma1 / xi) * z_T)
return float(delta_q)
except Exception:
return np.nan
def compute_delta_qT(row, T_choice, year_range, par_X_annees):
return delta_qT_X_years(
row["mu1"],
row["sigma1"],
row["xi"],
T=T_choice,
year_range=year_range,
par_X_annees=par_X_annees
)
# --- Espérence, variance, CV de GEV ---
def gev_moments(mu, sigma, xi):
if xi >= 0.5:
return np.nan, np.nan, np.nan # variance indéfinie
try:
mean = mu + sigma / xi * (gamma(1 - xi) - 1)
var = (sigma ** 2) / (xi ** 2) * (gamma(1 - 2 * xi) - gamma(1 - xi) ** 2)
cv = np.sqrt(var) / mean if mean != 0 else np.nan
return mean, var, cv
except Exception:
return np.nan, np.nan, np.nan
def eval_params_nsgev(mu0, mu1, sigma0, sigma1, xi, t, t0):
mu_t = mu0 + mu1 * (t - t0)
sigma_t = sigma0 + sigma1 * (t - t0)
return gev_moments(mu_t, sigma_t, xi)
def compute_delta_stat(row, stat: str, year_start: int, year_ref: int, year_end: int, par_X_annees: int) -> float:
"""
Calcule la variation du moment statistique GEV (moyenne, variance, CV)
exprimée en changement moyen par 10 ans.
Parameters:
- row : dictionnaire contenant les paramètres GEV
- stat : "ΔE", "ΔVar" ou "ΔCV"
- year_start, year_end : années de début et de fin
- year_ref : année de référence (t0)
Returns:
- Variation du moment sélectionné rapportée à 10 ans
"""
Δa = year_end - year_start
if Δa == 0:
return np.nan # évite division par zéro
# Moments aux deux dates
mean_start, var_start, cv_start = eval_params_nsgev(
mu0=row["mu0"], mu1=row.get("mu1", 0.0),
sigma0=row["sigma0"], sigma1=row.get("sigma1", 0.0),
xi=row["xi"], t=year_start, t0=year_ref
)
mean_end, var_end, cv_end = eval_params_nsgev(
mu0=row["mu0"], mu1=row.get("mu1", 0.0),
sigma0=row["sigma0"], sigma1=row.get("sigma1", 0.0),
xi=row["xi"], t=year_end, t0=year_ref
)
if stat == "ΔE":
return (mean_end - mean_start) * par_X_annees / Δa
elif stat == "ΔVar":
return (var_end - var_start) * par_X_annees / Δa
elif stat == "ΔCV":
return (cv_end - cv_start) * par_X_annees / Δa
else:
return np.nan
|