#!/usr/bin/env python3 """Recalcule les modèles simples des séries canadiennes de l'annexe Allison.""" import csv import sys def serie(value): if not value: return {} return {int(year): float(count) for year, count in (part.split(":", 1) for part in value.split(";"))} def attendu(annual, years, baseline, model): start, end = (int(part) for part in baseline.replace("–", "-").split("-")) points = [(year, annual[year]) for year in range(start, end + 1)] if model == "moyenne": mean = sum(value for _, value in points) / len(points) return sum(mean for _ in years) if model == "OLS": n = len(points) mean_x = sum(year for year, _ in points) / n mean_y = sum(value for _, value in points) / n slope = sum((year - mean_x) * (value - mean_y) for year, value in points) / sum((year - mean_x) ** 2 for year, _ in points) return sum(mean_y + slope * (year - mean_x) for year in years) raise ValueError(f"modèle inconnu: {model}") def main(path): failures = 0 with open(path, encoding="utf-8-sig", newline="") as source: for row in csv.DictReader(source): if ":" not in row["donnees_annuelles_utilisees"]: print(f'{row["claim_id"]} {row["modele"]}: non vérifié (série absente)') continue annual = serie(row["donnees_annuelles_utilisees"]) years = [int(year) for year in row["annees_cibles"].split(";")] observed = sum(annual[year] for year in years) projected = attendu(annual, years, row["periode_reference"], row["modele"]) excess = observed - projected ok = all(abs(value - float(row[key])) < 0.02 for value, key in ((observed, "observe_total"), (projected, "attendu_total"), (excess, "exces"))) failures += not ok print(f'{row["claim_id"]} {row["modele"]}: observé={observed:.3f} attendu={projected:.3f} écart={excess:.3f} {"OK" if ok else "ÉCART"}') return 1 if failures else 0 if __name__ == "__main__": raise SystemExit(main(sys.argv[1] if len(sys.argv) > 1 else "resultats-aggreges.csv"))