bdv / README.md
stephmnt's picture
Sync from GitHub Actions
46f9144 verified
---
title: Bdv
emoji: 🌍
colorFrom: green
colorTo: green
sdk: gradio
sdk_version: 6.2.0
app_file: app.py
pinned: false
---
# Elections Sète - Prévision municipales
Pipeline complet pour harmoniser les données électorales, construire un dataset panel sans fuite temporelle, entraîner des modèles multi-blocs, charger l'historique dans PostgreSQL et exposer des résultats via Gradio.
## Installation
- Python 3.10+ recommandé.
- `python3 -m venv .venv && source .venv/bin/activate`
- `pip install -r requirements.txt`
## Fichiers YAML (configuration)
### `config/communes.yaml`
Ce fichier définit **les communes à inclure** (codes INSEE). Il est consommé par le pipeline (`src.pipeline.run_full_pipeline`) pour filtrer les données au niveau commune.
Formats acceptés (les codes sont normalisés en 5 chiffres) :
```yaml
communes:
"34301": "Sète"
"34172": "Frontignan"
```
ou
```yaml
communes:
- code_insee: "34301"
nom: "Sète"
- "34172"
```
Si tu modifies ce fichier, il faut **relancer le pipeline** pour régénérer les données filtrées.
### `config/raw_sources.yaml`
Description des fichiers bruts et de leur structure (colonnes, séparateur, métadonnées).
C'est **le point d'entrée** pour ajouter un nouveau CSV au pipeline.
Exemple (copie d'une election precedente + ajustements) :
```yaml
24_L_T1.csv:
copy_from: 22_L_T1.csv
date_scrutin: "2024-06-30"
code_bv_cols: ["Code commune", "Code BV"]
rename_map:
Nuance Liste: code_candidature
Libellé Abrégé Liste: nom_candidature
```
### `config/nuances.yaml`
Mapping des nuances vers les blocs politiques (avec overrides).
Par défaut, le mapping CSV historique est réutilise et on peut **surcharger** ou **ajouter** des nuances :
```yaml
base_mapping: data/mapping_candidats_blocs.csv
overrides:
- code_candidature: "XYZ"
nom_candidature: "Exemple"
blocs: [gauche_modere, centre]
```
### `docker-compose.yml`
Fichier YAML pour démarrer PostgreSQL (et éventuellement pgAdmin). Utilisé par :
```bash
docker-compose up -d postgres
docker-compose --profile admin up
```
## 1. Prétraitement (harmonisation)
```bash
# Harmonisation des CSV bruts -> data/interim/elections_long.parquet
python -m src.data.preprocess --raw-dir data/raw --output-dir data/interim
```
Par défaut, le prétraitement lit `config/raw_sources.yaml`. Tu peux surcharger via `--meta-config`.
## 2. Pipeline communes + features (optionnel mais recommandé si tu filtres par communes)
Le pipeline applique le filtre `config/communes.yaml` et génère `data/processed/elections_blocs.*`.
À lancer depuis un notebook ou un petit script :
```bash
python3 - <<'PY'
from pathlib import Path
from src.pipeline import run_full_pipeline
run_full_pipeline(
elections_long_path=Path("data/interim/elections_long.parquet"),
mapping_path=Path("config/nuances.yaml"),
output_dir=Path("data/processed"),
target_communes_path=Path("config/communes.yaml"),
)
PY
```
## 3. Construction du panel (features + cibles)
```bash
python -m src.features.build_features \
--elections-long data/interim/elections_long.parquet \
--mapping config/nuances.yaml \
--output data/processed/panel.parquet
```
Le dictionnaire de données est généré dans `data/processed/data_dictionary.md`.
Note : `src.features.build_features` **ne filtre pas** via `config/communes.yaml`. Si tu veux limiter l'entraînement à certaines communes, filtre `elections_long` en amont ou adapte le pipeline.
## 4. Base PostgreSQL
```bash
cp .env.example .env
docker-compose up -d postgres # pgAdmin en option: `docker-compose --profile admin up`
# Ingestion du panel dans le schéma normalisé
python -m src.db.ingest --input data/processed/panel.parquet
```
Le schéma est défini dans `src/db/schema.py`.
## 5. Entraînement & évaluation
Commande demandée (CV stricte par scrutin) :
```bash
python3 -m src.model.train --cv-splits 4 --models hist_gradient_boosting
```
Options principales :
- `--panel` : chemin du panel (`data/processed/panel.parquet` par défaut).
- `--models-dir` / `--reports-dir` : sorties modèles et rapports.
- `--train-end-year`, `--valid-end-year`, `--test-start-year` : split temporel.
- `--cv-splits` : nb de folds temporels (par scrutin).
- `--no-tune` : désactive la grille d'hyperparamètres.
- `--max-trials` : limite le nombre d'essais par modèle.
- `--models` : liste de modèles à tester (ex: `ridge`, `hist_gradient_boosting`, `lightgbm`, `xgboost`, `two_stage_hgb`, `catboost`).
Sorties :
- Modèle + preprocessor : `models/<nom>.joblib` et `models/feature_columns.json`
- Modèle sélectionné : `models/best_model.json`
- Rapport métriques : `reports/metrics.json` et `reports/metrics.md`
- CV détaillée : `reports/cv_summary.csv`
- Figure : `reports/figures/mae_per_category.png`
- Model card : `models/model_card.md`
## 6. Génération de prédictions hors ligne
```bash
python -m src.model.predict \
--model-path models/hist_gradient_boosting.joblib \
--target-election-type municipales \
--target-year 2026 \
--commune-code 34301
# -> predictions/pred_municipales_2026_sete.csv
```
Cette commande produit des **parts (%)** et des deltas vs législatives et municipales 2020.
## 7. Application Gradio
```bash
python -m app.gradio_app
```
Comportement :
- Backend PostgreSQL si disponible, sinon fallback fichiers locaux.
- **Historique** : consultation bureau par bureau (pas de ML).
- **Prédiction** : parts par bloc converties en **comptes** (personnes) + `blancs`, `nuls`, `abstentions`.
- `inscrits` peut être fourni par l'utilisateur (sinon valeur historique la plus récente du bureau).
- Cibles proposées : municipales 2026 (tour 1), legislatives 2027 (tour 1), presidentielles 2027 (tour 1).
## Structure des données
- Configurations : `config/`
- Bruts : `data/raw/`
- Long harmonisé : `data/interim/elections_long.parquet`
- Élections blocs (filtrées) : `data/processed/elections_blocs.parquet`
- Stats communales par scrutin : `data/processed/commune_event_stats.parquet`
- Panel features+cibles : `data/processed/panel.parquet`
- Mapping nuances -> catégories : `config/nuances.yaml` (base: `data/mapping_candidats_blocs.csv`)
## Notes
- Aucune fuite temporelle : les features sont calculées uniquement sur des scrutins strictement antérieurs à la cible.
- Les parts sont clipées à [0, 1] puis renormalisées.
- Les blancs/nuls dépendent des colonnes disponibles dans l'historique ; si une source ne les fournit pas, ils seront à 0.
## Inventaire des fichiers (snapshot)
Statuts :
- `actif` : utilisé par le pipeline actuel.
- `généré` : produit par le pipeline/entraînement (recréable).
- `hérité (début projet)` : ancien fichier ou prototype.
- `optionnel` : utile mais non requis au runtime.
- `système (inutile)` : métadonnées OS.
| Fichier | Fonction | Statut |
|---|---|---|
| `.DS_Store` | Métadonnées macOS | système (inutile) |
| `.env.example` | Template des variables d'environnement (DB) | actif |
| `.gitignore` | Règles gitignore | actif |
| `Elections_Sete.code-workspace` | Config VSCode (workspace) | optionnel |
| `README.md` | Documentation projet | actif |
| `app/__init__.py` | Package app (init) | actif |
| `app/app.py` | Ancienne app Gradio (bv_features.parquet) | hérité (début projet) |
| `app/gradio_app.py` | Application Gradio principale | actif |
| `app.py` | Ancienne interface Gradio (compute_predictions) | hérité (début projet) |
| `catboost_info/catboost_training.json` | Artefacts CatBoost (logs/metrics) | généré |
| `catboost_info/learn/events.out.tfevents` | Artefacts CatBoost (logs/metrics) | généré |
| `catboost_info/learn_error.tsv` | Artefacts CatBoost (logs/metrics) | généré |
| `catboost_info/time_left.tsv` | Artefacts CatBoost (logs/metrics) | généré |
| `config/communes.yaml` | Liste des communes cibles (codes INSEE) | actif |
| `config/nuances.yaml` | Overrides mapping nuances -> blocs | actif |
| `config/raw_sources.yaml` | Schéma des CSV bruts (meta-config) | actif |
| `data/.DS_Store` | Métadonnées macOS | système (inutile) |
| `data/contours-france-entiere-latest-v2.geojson` | Fond cartographique (geojson) | optionnel |
| `data/interim/.DS_Store` | Métadonnées macOS | système (inutile) |
| `data/interim/candidates_long.parquet` | Données intermédiaires long format | généré |
| `data/interim/elections_long.csv` | Données intermédiaires long format | généré |
| `data/interim/elections_long.parquet` | Données intermédiaires long format | généré |
| `data/interim/frames_std/14_EU.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/14_MN14_T1T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/17_L_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/17_L_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/17_PR_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/17_PR_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/19_EU.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/20_MN_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/20_MN_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/21_DEP_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/21_DEP_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/21_REG_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/21_REG_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/22_L_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/22_L_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/22_PR_T1.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/22_PR_T2.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/frames_std/24_EU.parquet` | Intermédiaire standardisé par scrutin | généré |
| `data/interim/harmonized/14_EU_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/14_MN14_T1T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/17_L_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/17_L_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/17_PR_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/17_PR_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/19_EU_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/20_MN_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/20_MN_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/21_DEP_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/21_DEP_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/21_REG_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/21_REG_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/22_L_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/22_L_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/22_PR_T1_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/22_PR_T2_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/harmonized/24_EU_harmonized.csv` | CSV harmonisé par scrutin | généré |
| `data/interim/unmapped_nuances.csv` | Données intermédiaires long format | généré |
| `data/mapping_candidats_blocs.csv` | Mapping nuances -> blocs (base) | actif |
| `data/mappings/category_mapping.csv` | Copie/variante de mapping | hérité (début projet) |
| `data/processed/bv_features.parquet` | Features legacy (utilisées par app/app.py) | hérité (début projet) |
| `data/processed/data_dictionary.md` | Dictionnaire de données généré | généré (doc) |
| `data/processed/elections_blocs.csv` | Dataset blocs (filtré communes) | généré (utilisé) |
| `data/processed/elections_blocs.parquet` | Dataset blocs (filtré communes) | généré (utilisé) |
| `data/processed/history_cache.parquet` | Cache local (historique/prédictions) | généré (cache) |
| `data/processed/panel.csv` | Panel features+cibles | généré (utilisé) |
| `data/processed/panel.parquet` | Panel features+cibles | généré (utilisé) |
| `data/processed/predictions_cache.parquet` | Cache local (historique/prédictions) | généré (cache) |
| `data/processed/predictions_municipales_2026.csv` | Exports de prédictions | généré (résultats) |
| `data/processed/predictions_municipales_2026_blocs.csv` | Exports de prédictions | généré (résultats) |
| `data/processed/predictions_municipales_sete_2026.csv` | Exports de prédictions | généré (résultats) |
| `data/raw/14_EU.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/14_MN14_T1T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/17_L_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/17_L_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/17_PR_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/17_PR_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/19_EU.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/20_MN_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/20_MN_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/21_DEP_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/21_DEP_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/21_REG_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/21_REG_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/22_L_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/22_L_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/22_PR_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/22_PR_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/24_EU.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/24_L_T1.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `data/raw/24_L_T2.csv` | Données brutes (entrée prétraitement) | actif (entrée pipeline) |
| `datasets/.DS_Store` | Métadonnées macOS | système (inutile) |
| `datasets/14_EU.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/14_MN14_T1T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/17_L_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/17_L_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/17_PR_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/17_PR_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/19_EU.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/20_MN_T1.tsv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/20_MN_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/21_DEP_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/21_DEP_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/21_REG_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/21_REG_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/22_L_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/22_L_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/22_PR_T1.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/22_PR_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/24_EU.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/24_L_T1T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `datasets/24_L_T2.csv` | Copie brute des datasets (ancienne structure) | hérité (début projet) |
| `docker-compose.yml` | Services Docker (PostgreSQL/pgAdmin) | actif |
| `harmoniser.md` | Notes d'harmonisation | optionnel |
| `main.py` | Orchestrateur pipeline (CLI utilitaire) | optionnel |
| `mission.md` | Backlog / notes projet | optionnel |
| `models/best_model.json` | Nom du meilleur modèle | généré (utilisé) |
| `models/feature_columns.json` | Liste des features du modèle | généré (utilisé) |
| `models/hist_gradient_boosting.joblib` | Modèle entraîné | généré (utilisé) |
| `models/model_card.md` | Model card (synthèse) | généré (doc) |
| `notebooks/01_pretraitement.ipynb` | Notebook d'analyse / exploration | optionnel (exploration) |
| `notebooks/02_feature_engineering.ipynb` | Notebook d'analyse / exploration | optionnel (exploration) |
| `notebooks/03_modelisation_prediction.ipynb` | Notebook d'analyse / exploration | optionnel (exploration) |
| `notebooks/aed.ipynb` | Notebook d'analyse / exploration | optionnel (exploration) |
| `notebooks/catboost_info/catboost_training.json` | Artefacts CatBoost (notebook) | généré |
| `notebooks/catboost_info/learn/events.out.tfevents` | Artefacts CatBoost (notebook) | généré |
| `notebooks/catboost_info/learn_error.tsv` | Artefacts CatBoost (notebook) | généré |
| `notebooks/catboost_info/time_left.tsv` | Artefacts CatBoost (notebook) | généré |
| `output/.DS_Store` | Métadonnées macOS | système (inutile) |
| `output/Sans titre 2.png` | Exports graphiques | hérité (début projet) |
| `output/Sans titre 3.png` | Exports graphiques | hérité (début projet) |
| `output/Sans titre 4.png` | Exports graphiques | hérité (début projet) |
| `output/Sans titre 5.png` | Exports graphiques | hérité (début projet) |
| `output/Sans titre 6.png` | Exports graphiques | hérité (début projet) |
| `output/Sans titre.png` | Exports graphiques | hérité (début projet) |
| `output/output.png` | Exports graphiques | hérité (début projet) |
| `predictions/pred_municipales_2026_sete.csv` | Exports de prédictions | généré (résultats) |
| `reports/colonnes_comparatif.csv` | Rapport / métriques | généré |
| `reports/cv_summary.csv` | Rapport / métriques | généré |
| `reports/figures/mae_per_category.png` | Figures de rapports | généré |
| `reports/metrics.json` | Rapport / métriques | généré |
| `reports/metrics.md` | Rapport / note analytique | généré (doc) |
| `reports/notebook_audit.md` | Rapport / note analytique | généré (doc) |
| `requirements.txt` | Dépendances Python | actif |
| `src/__init__.py` | Package src (init) | actif |
| `src/constants.py` | Constantes projet | actif |
| `src/data/__init__.py` | Module data | actif |
| `src/data/preprocess.py` | Prétraitement/harmonisation | actif |
| `src/data_prep.py` | Librairie d'harmonisation des données | actif |
| `src/database.py` | Accès base SQL (fallback/app) | actif |
| `src/db/__init__.py` | Module DB | actif |
| `src/db/ingest.py` | Ingestion PostgreSQL | actif |
| `src/db/schema.py` | Schéma PostgreSQL | actif |
| `src/features/__init__.py` | Module features | actif |
| `src/features/build_features.py` | Construction du panel features+cibles | actif |
| `src/model/predict.py` | Prédiction hors ligne | actif |
| `src/model/train.py` | Entraînement + CV | actif |
| `src/pipeline.py` | Pipeline de construction (blocs + stats) | actif |
| `src/prediction.py` | Prédiction legacy (app.py) | hérité (début projet) |
| `supports/Plan-2024_Bureaux-de-vote.pdf` | Documents de référence | optionnel |
| `supports/zonages_admin_canton.pdf` | Documents de référence | optionnel |