paco-dev #2

Merged
pgoze-ensae merged 39 commits from paco-dev into main 2026-04-13 21:51:04 +02:00
Showing only changes of commit 4d1e08274e - Show all commits

View File

@ -15,8 +15,8 @@ import s3fs
# ─────────────────────────────────────────────
# PARAMÈTRES
# ─────────────────────────────────────────────
ALPHA = 0.03 # tolérance réconciliation : 3% du stock à t
MIN_AUM_EUR = 5e6 # seuil filtrage étape 1 — 0 pour les heads de test
ALPHA = 0.03 # tolérance réconciliation : 5% du stock à t
MIN_AUM_EUR = 0 # seuil filtrage étape 1 — 0 pour les heads de test, 5e6 en prod
MIN_JACCARD = 0.3 # seuil minimal similarité portefeuille pour chirurgie
SCORE_DROP_THRESHOLD = 0.1 # si score chute de >10% → candidat chirurgie
@ -25,7 +25,7 @@ EXCLUDE_REGISTRAR = ["Off Distribution", "Private Clients"]
# ─────────────────────────────────────────────
# 1. CHARGEMENT
# ─────────────────────────────────────────────
def load_data(aum_path, flows_path):
def load_data():
fs = s3fs.S3FileSystem(
client_kwargs={'endpoint_url': 'https://'+'minio-simple.lab.groupe-genes.fr'},
key = os.environ["AWS_ACCESS_KEY_ID"],
@ -501,8 +501,11 @@ def run_surgery_pass(scores_history, errors_history, panel, monthly_flows,
# ── ISIN du compte courant à t_curr (pour pré-filtre) ──
isin_curr = reg_isin_at_date.get(reg_curr, {}).get(t_curr, set())
# ── Candidats disponibles (non déjà mappés) ──
available = all_regs_in_panel - set(mapping_inv.keys()) - {reg_curr}
# ── Candidats disponibles ──
# On exclut les codes déjà mappés à un autre compte,
# mais reg_curr lui-même est un candidat valide (self-mapping :
# le compte existait déjà sous ce code à t-1, dormant ou partiel).
available = (all_regs_in_panel - set(mapping_inv.keys())) | {reg_curr}
best_candidate = None
best_score_after = score_prev_no_surgery # baseline = pas de chirurgie
@ -549,6 +552,9 @@ def run_surgery_pass(scores_history, errors_history, panel, monthly_flows,
f"score {score_curr:.4f}{best_score_after:.4f})")
# Mise à jour mapping
# Si self-mapping (best_candidate == reg_curr), on ne touche pas
# mapping_inv car le code ne change pas — on met juste à jour le score.
if best_candidate != reg_curr:
if reg_curr in mapping_inv:
del mapping_inv[reg_curr]
mapping_inv[best_candidate] = reg_orig
@ -617,13 +623,13 @@ def export_results(scores_history, mapping_history, surgery_log, all_months, out
# ─────────────────────────────────────────────
# 8. PIPELINE PRINCIPAL
# ─────────────────────────────────────────────
def run_pipeline(aum_path, flows_path):
def run_pipeline():
print("=" * 60)
print("CARMIGNAC — Pipeline de réparation des Registrar IDs")
print("=" * 60)
# Chargement
aum, flows = load_data(aum_path, flows_path)
aum, flows = load_data()
# Étape 1 — Univers de référence
aum_ref, weights, universe, t_ref = build_reference_universe(aum)
@ -673,7 +679,4 @@ def run_pipeline(aum_path, flows_path):
if __name__ == "__main__":
df_scores, df_mapping, surgery_log, scores_history, mapping_history = run_pipeline(
"s3://projet-bdc-data/carmignac/AUM ENSAE V2 -20251105.csv",
"s3://projet-bdc-data/carmignac/Flows ENSAE V2 -20251105.csv"
)
df_scores, df_mapping, surgery_log, scores_history, mapping_history = run_pipeline()