SPB Git
6.3 KB · 91 lines python
1#!/usr/bin/env python32"""Chapitre 10 — statistiques descriptives de la matrice des dispositions normatives du domaine C3(sources/normes-C.csv : 100 dispositions vérifiées le 2026-10-31) et chronologie documentaire des cadres normatifs4(dates tirées de sources/registry-C.csv). Imprime les chiffres cités au chapitre 10.56Usage (racine du dépôt) : PYTHONPATH=analysis/python python3 analysis/python/cases/ch10_matrice_normes.py"""7from __future__ import annotations8import sys, pathlib, datetime as dt9import pandas as pd1011sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))12ROOT = pathlib.Path(__file__).resolve().parents[3]13MATRICE = ROOT / "sources/normes-C.csv"1415# Regroupement des 17 domaines de la matrice en six familles (choix de présentation de l'auteur)16FAMILLES = {17    "OEAQ-NPP": "OEAQ — normes de pratique", "OEAQ-Déontologie": "OEAQ — déontologie",18    "OEAQ-Règlements": "OEAQ — règlements", "Code des professions": "OEAQ — règlements",19    "IVS": "Cadres hors Québec", "CUSPAP": "Cadres hors Québec", "USPAP": "Cadres hors Québec",20    "RICS": "Cadres hors Québec", "IAAO": "Cadres hors Québec",21    "Banque du Canada": "Finance et prudentiel", "BSIF": "Finance et prudentiel", "Finances Canada": "Finance et prudentiel",22    "SCHL": "Finance et prudentiel",23    "Statistique Canada": "Données de marché", "APCIQ": "Données de marché", "JLR": "Données de marché",24    "Teranet–BNC": "Données de marché",25}2627# Chronologie documentaire (source_id du registre C ; dates vérifiées le 2026-10-31).28# publication : date de publication connue (None si non documentée) ; effet : date d'entrée en vigueur ;29# fin : fin de validité connue (None = en vigueur au 2026-10-31) ; statut : en_vigueur | remplace | projet | reference30CADRES = [31    dict(cadre="IAAO — Standard on AVMs (rév. 2018)", source="SRC-C-026", publication=None, effet=dt.date(2018, 7, 1), fin=None, statut="reference", precision="mois"),32    dict(cadre="IAAO — Standard on Ratio Studies (2013)", source="SRC-C-024", publication=None, effet=dt.date(2013, 4, 1), fin=None, statut="reference", precision="mois"),33    dict(cadre="IAAO — Standard on Mass Appraisal (rév. 2025)", source="SRC-C-025", publication=None, effet=dt.date(2025, 1, 1), fin=None, statut="reference", precision="annee"),34    dict(cadre="USPAP 2024 (États-Unis)", source="SRC-C-021", publication=None, effet=dt.date(2024, 1, 1), fin=None, statut="en_vigueur", precision="jour", verification="partielle"),35    dict(cadre="CUSPAP 2024 (Canada)", source="SRC-C-020", publication=None, effet=dt.date(2024, 1, 1), fin=dt.date(2026, 3, 31), statut="remplace", precision="jour"),36    dict(cadre="NPP de l'OEAQ (Québec)", source="SRC-C-001", publication=None, effet=dt.date(2024, 2, 1), fin=None, statut="en_vigueur", precision="jour"),37    dict(cadre="IVS 2025 (IVSC)", source="SRC-C-014", publication=dt.date(2024, 1, 31), effet=dt.date(2025, 1, 31), fin=None, statut="en_vigueur", precision="jour"),38    dict(cadre="RICS Red Book Global (2025)", source="SRC-C-023", publication=dt.date(2024, 12, 11), effet=dt.date(2025, 1, 31), fin=None, statut="en_vigueur", precision="jour"),39    dict(cadre="CUSPAP 2026 (Canada)", source="SRC-C-018", publication=None, effet=dt.date(2026, 4, 1), fin=None, statut="en_vigueur", precision="jour"),40    dict(cadre="IVS 2028 — projet (exposure draft)", source="SRC-C-015", publication=dt.date(2026, 1, 1), effet=dt.date(2028, 1, 31), fin=None, statut="projet", precision="mois"),41]42DATE_REF = dt.date(2026, 10, 31)4344def charger() -> pd.DataFrame:45    m = pd.read_csv(MATRICE)46    m["famille"] = m["domaine"].map(FAMILLES)47    assert m["famille"].notna().all(), "domaine sans famille"48    m["n_chapitres"] = m["chapitres"].str.split(";").apply(len)49    m["ch10"] = m["chapitres"].str.contains("ch10")50    return m5152def statistiques(m: pd.DataFrame) -> dict:53    par_domaine = m["domaine"].value_counts()54    par_famille = m["famille"].value_counts()55    par_chapitre = m["chapitres"].str.split(";").explode().value_counts()56    oeaq = m["domaine"].str.startswith("OEAQ") | (m["domaine"] == "Code des professions")57    return {58        "n": len(m), "n_domaines": m["domaine"].nunique(), "n_chapitres_couverts": par_chapitre.size,59        "par_domaine": par_domaine, "par_famille": par_famille, "par_chapitre": par_chapitre,60        "n_oeaq": int(oeaq.sum()), "part_oeaq": float(oeaq.mean()),61        "n_ch10": int(m["ch10"].sum()), "part_ch10": float(m["ch10"].mean()),62        "ch10_par_domaine": m.loc[m["ch10"], "domaine"].value_counts(),63        "moy_chapitres_par_disposition": float(m["n_chapitres"].mean()),64        "max_chapitres_par_disposition": int(m["n_chapitres"].max()),65        "part_multi_chapitres": float((m["n_chapitres"] > 1).mean()),66    }6768def chronologie() -> pd.DataFrame:69    c = pd.DataFrame(CADRES)70    c["en_vigueur_2026_10_31"] = c.apply(lambda r: r["effet"] <= DATE_REF and (r["fin"] is None or r["fin"] >= DATE_REF) and r["statut"] != "projet", axis=1)71    c["delai_publication_effet_jours"] = c.apply(lambda r: (r["effet"] - r["publication"]).days if r["publication"] else None, axis=1)72    return c7374def main(verbose: bool = True) -> dict:75    m = charger(); st = statistiques(m); ch = chronologie()76    if verbose:77        print(f"== Matrice C : {st['n']} dispositions, {st['n_domaines']} domaines, {st['n_chapitres_couverts']} chapitres couverts")78        print("== Par famille :\n", st["par_famille"].to_string())79        print("== Par domaine :\n", st["par_domaine"].to_string())80        print(f"== Dispositions OEAQ + Code des professions : {st['n_oeaq']} ({st['part_oeaq']*100:.0f} %)")81        print(f"== Dispositions renvoyant au ch. 10 : {st['n_ch10']} ({st['part_ch10']*100:.0f} %) ; par domaine :\n", st["ch10_par_domaine"].to_string())82        print("== Dix chapitres les plus cités :\n", st["par_chapitre"].head(10).to_string())83        print(f"== Chapitres par disposition : moyenne {st['moy_chapitres_par_disposition']:.2f}, max {st['max_chapitres_par_disposition']}, "84              f"part multi-chapitres {st['part_multi_chapitres']*100:.0f} %")85        pd.set_option("display.width", 200)86        print("== Chronologie des cadres (registre C) :\n", ch[["cadre", "publication", "effet", "fin", "statut", "en_vigueur_2026_10_31", "delai_publication_effet_jours"]].to_string(index=False))87    return {"matrice": m, "stats": st, "chronologie": ch}8889if __name__ == "__main__":90    main()91
Files · main
Menu

Theme