--- title: Attrition API (FastAPI) colorFrom: purple colorTo: indigo sdk: docker pinned: false --- # Prédiction de l’Attrition des Employés – TechNova Partners Bienvenue dans ce projet de **classification en Machine Learning** dont l’objectif est d’**analyser et prédire les démissions d’employés (attrition)** au sein de l’ESN _TechNova Partners_, spécialisée dans le conseil en transformation digitale et la vente de solutions SaaS. Ce dépôt contient l’ensemble du travail réalisé en tant que **Consultant Data Scientist** pour : - comprendre les **facteurs clés** derrière les démissions, - construire un **modèle de prédiction de l’attrition**, - produire des **insights actionnables** pour les équipes RH ## Table des Matières - [Contexte & objectifs](#-contexte) - [Jeux de données](#-jeux-de-données) - [Approche](#-approche) - [Structure du dépôt](#️-structure-du-dépôt) - [Mise en place du modèle](#-mise-en-place-du-modèle) - [API(FastAPI)](#-api-fastapi-api) - [Base de donées PostgreSQL](#-base-de-données-postgresql) - [Installation](#️-installation) - [Utilisation](#️-utilisation) - [Workflow Git](#workflow-git-branches--commits--tags-workflow) - [Traçabilité des prédictions](#traçabilité-des-prédiction) - [Tests & Couverture (CI)](#tests--couverture-ci) - [Déploiement(CI/CD)](#déploiement-cd-vers-hugging-face-spaces) - [Déploiment HF Spaces (Docker)](#déploiement-hf-spaces-docker) - [Livrables](#-livrables) - [Auteur](#-auteur) --- ## Contexte & objectifs **Problème** : anticiper les départs d’employés (attrition) et expliquer les facteurs clés. **Objectifs**: - Construire un **pipeline scikit-learn** (prétraitements + modèle RF) - Exposer une **API ** (FastAPI) avec Swagger/OpenAPI. - Tracer chaque prédiction (inputs/outputs) dans **PostgreSQL** - Mettre en place **CI** (tests) et **CD** (déploiement automatique). --- ## Jeux de données Trois sources principales sont mises à disposition : 1. **SIRH**: poste, département, contrat, âge, ancienneté, salaire, etc. 2. **Évaluations de performance**: notes annuelles, engagement/satisfaction, historiques RH. 3. **Sondage annuel employés**: bien-être, charge, management, équilibre vie pro/perso. **Variable cible** (attrition = 1/0) Ces différentes sources sont **fusionnées et préparées** pour construire un dataset modélisable. Fichier aligné pour l’inférence : `data/processed/df_central_norm.csv` (contient le **feature engineering** attendu par le pipeline et les schémas SQL). --- ## Approche - **Préparation** : encodages catégoriels, normalisation, features (`exp_moins_3_years`, etc.). - **Modèle** : `RandomForestClassifier` dans un Pipeline scikit-learn. - **API** : FastAPI + endpoints `predict_one` et `predict_proba`. - **Traçabilité** : table `ml.predictions_log` (inputs/outputs/threshold). - **Déploiement** : Docker → Hugging Face Spaces (CD GitHub Actions). - **Qualité** : Pytest + couverture, règles de branche et PR. --- ## Structure du dépôt ```text . ├── src/ │ ├── __init__.py │ ├── data_preparation.py. # chargement & split X/y (données traitées) │ ├── train_model.py # entraînement + sauvegarde artefact │ └── utils.py # utilitaires (chargement modèle, prédiction unitaire) ├── tests/ │ ├── test_data_preparation.py │ └── test_predict.py ├── models/ # artefact modèle ├── data/ │ ├── raw/ # fichiers brutsv(privé, ignoré) – .gitkeep │ └── processed/ # données traités (visibles) ├── db/ │ ├── attrition_local.session.sql # schémas hr_staging/hr/ml + indexes + logs │ ├── create_db.py # création table + exemple │ └── load_csv.py # chargement CSV → hr.employees ├── notebooks/ │ ├── 01_analyse_exploratoire.ipynb │ ├── 02_preprocessing.ipynb │ └── 03_modelisation.ipynb ├── .github/workflows/ │ ├── ci.yml │ └── deploy-to-hf-space.yml ├── main.py # entraînement ├── pyproject.toml # configuration de l'environnement & dépendances ├── requirements.txt. # exporté depuis uv ├── README.md ├── .gitignore └── uv.lock ├── Dockerfile # verrouillage précis des versions ``` ## Mise en place du modèle - **Entraînement** : notebooks 01_analyse_exploratoire.ipynb, 02_preprocessing.ipynb et 03_modelisation.ipynb. - **Artefact modèle** : `model.joblib` (hébergé sur Hugging Face Hub, téléchargé à l’inférence). - **Chargement côté API** : si `models/model.joblib` est absent, l’API télécharge depuis `veranoscience/attrition-model`. - **Seuil** : `THRESHOLD=0.33` → `pred` = (proba >= 0.33)`. --- ## API (FastAPI) - **Doc Swagger** : `/docs` - **Endpoints principaux** : `GET /health` → statut, source du modèle (local ou hub), threshold. `POST /predict_one` → prédiction unitaire (retourne proba et pred). `POST /predict_proba` → prédictions batch (retourne listes probas et preds). Exemple : ```bash curl -s -X POST http://127.0.0.1:8000/predict_one \ -H "Content-Type: application/json" \ -d '{ "age":41, "genre":"F", "revenu_mensuel":6000, "statut_marital":"Célibataire", "departement":"Consulting", "poste":"Consultant", "nombre_experiences_precedentes":6, "annees_dans_le_poste_actuel":2, "note_evaluation_precedente":3, "note_evaluation_actuelle":3, "heure_supplementaires":0, "augementation_salaire_precedente":12, "nombre_participation_pee":1, "nb_formations_suivies":2, "distance_domicile_travail":5, "niveau_education":2, "annees_depuis_la_derniere_promotion":1, "annes_sous_responsable_actuel":2, "satisfaction_globale":3.0, "exp_moins_3_years":0, "domaine_etude":"Infra & Cloud", "frequence_deplacement":"Occasionnel" }' # → {"threshold":0.33,"proba":0.1443,"pred":0} ``` --- ## Base de données PostgreSQL **Objectif** : assurer une traçabilité complète des échanges API ↔ modèle. - Schémas : `hr_staging` : réception brute (employees_raw). `hr` : table typée finale (employees) + index. `ml` : table de log des inférences (predictions_log) + index. - Scripts : `db/attrition_local.session.sql` → crée schémas/tables/index. `db/load_csv.py` → charge `data/processed/df_central_norm.csv` dans hr.employees. `db/create_db.py` → exemple alternatif (table simple predictions + insertion d’une ligne). Activation du logging DB côté API (local) : ```bash export DATABASE_URL="postgresql+psycopg2://appuser:appuser@localhost:5432/attrition" uvicorn src.api.server:app --reload # Chaque appel /predict_* crée une ligne dans ml.predictions_log ``` --- ## Installation locale **Prérequis** - Python 3.10+ - git - [uv](https://github.com/astral-sh/uv) - PostgreSQL 15 local (macOS : `brew install postgresql@15`) ## Setup Python ```bash uv venv && source .venv/bin/activate uv sync ``` ## Démarrer l'API ```bash uvicorn src.api.server:app --reload # Swagger: http://127.0.0.1:8000/docs ``` --- ## Utilisation 1. Lancer les notebooks Depuis la racine du projet, avec l’environnement activé : ```bash jupyter notebook ``` Puis ouvrir: - `notebooks/01_analyse_exploratoire.ipynb` pour l’analyse exploratoire - `notebooks/02_preprocessing.ipynb` pour le nettoyage & feature engineering - `notebooks/03_modelisation.ipynb` pour la modélisation et SHAP Script (entrai&nement rapide) ```bash python main.py ``` Un artefact est sauvegardé dans `models/model.joblib` Healthcheck ```bash curl -s http://127.0.0.1:8000/health | jq ``` Batch ```bash curl -s -X POST http://127.0.0.1:8000/predict_proba \ -H "Content-Type: application/json" \ -d '{"inputs":[{ ... les mêmes champs que /predict_one ... }]}' ``` --- ## Workflow Git (branches / commits / tags) - Branche principale : `main` (protégée) - Conventions de branches : `<-resume->` - Types : `feat`, `fix`, `docs`, `refactor`, `chore`, `test`, `data` - Examples : `docs/mise-a-jour-readme` - Commits descriptifs: `feat: ...`, `chore: ...` - Tags de version : `v0.1.0`, `v0.2.0`, ... - Créer : `git tag -a v0.1.0 -m "v0.1.0: base"` - Pousser : `git push origin v0.1.0` Résolution de conflits : utiliser l’outil intégré **VS Code** (Accept Current/Incoming → `git add .` → `git rebase --continue`). --- ## Traçabilité des prédictions Activation : définir la variable d’env. `DATABASE_URL` avant de lancer l’API. ```bash export DATABASE_URL="postgresql+psycopg2://appuser:appuser@localhost:5432/attrition" uvicorn src.api.server:app --reload ``` À chaque appel réussi : insertion dans `ml.predictions_log` (date, payload, proba, classe, seuil, statut). Requête de contrôle : ```sql SELECT created_at, proba, pred, threshold, status FROM ml.predictions_log ORDER BY created_at DESC LIMIT 5; ``` --- ### Tests & Couverture (CI) Lancer localement : ```bash uv run pytest # avec couverture: uv run pytest --cov=src --cov-report=term-missing ``` CI GitHub Actions (`.github/workflows/ci.yml`) : - installe l’environnement, - exécute Pytest, - calcule la couverture, - bloque la PR si la CI échoue. --- ## Déploiement (CD) vers Hugging Face Spaces - **Dockerfile** à la racine. - Workflow `deploy-to-hf-space.yml` : - clone le repo du Space, - copie `Dockerfile`, `pyproject.toml`, `src/, db/, README.md`, etc., - push vers le Space → rebuild automatique → API en ligne. Secrets requis (GitHub → Settings → Secrets and variables → Actions) : - `HF_TOKEN` : token Hugging Face (scope write). - `HF_SPACE_SLUG` : slug owner/SpaceName (ex. veranoscience/OpenClassroomsProject). Cycle CD : 1. Crée une branche → commit → PR. 2. Merge vers `main`. 3. L’Action CD se lance et déploie sur le Space. ## Déploiement HF Spaces (Docker) - Dockerfile à la racine. Le Space utilise `sdk: docker`. Port par défaut `7860`. L’API est servie par Uvicorn. Modèle téléchargé au démarrage si absent localement. --- ## Livrables Le projet fournit : 1. Dépôt Git structuré : code source, `pyproject.toml`, historique (branches/PR/tags), README. 2. API FastAPI fonctionnelle, documentée (Swagger), déployée (Docker + HF Spaces). 3. Tests Pytest + rapport de couverture (via CI). 4. Base PostgreSQL : schémas SQL, scripts de création/chargement, logs d’inférence. 5. CI/CD : GitHub Actions (CI PR & CD déploiement auto). --- --- ## Auteur Projet pédagogique - Ksenia Dautel