Spaces:
Sleeping
Sleeping
GitLab CI commited on
Commit ·
2edd2e3
1
Parent(s): d6af6ed
Déploiement automatique depuis GitLab CI - 2026-02-21 15:01:29
Browse files- 2_Data_transformed/shap_feature_importance.csv +11 -0
- Dockerfile +1 -0
- api.py +45 -8
2_Data_transformed/shap_feature_importance.csv
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Feature;SHAP_Importance
|
| 2 |
+
EXT_SOURCE_3;0.06643797108437811
|
| 3 |
+
EXT_SOURCE_2;0.05505396045357957
|
| 4 |
+
EXT_SOURCE_1;0.03233115507717239
|
| 5 |
+
DAYS_EMPLOYED;0.028354028645426625
|
| 6 |
+
PAYMENT_RATE;0.022252903274004247
|
| 7 |
+
INSTAL_DPD_MEAN;0.018776079308394894
|
| 8 |
+
PREV_CNT_PAYMENT_MEAN;0.01790142297206313
|
| 9 |
+
AMT_ANNUITY;0.016378318169115513
|
| 10 |
+
CODE_GENDER;0.015840633691170735
|
| 11 |
+
PREV_NAME_PRODUCT_TYPE_walk-in_MEAN;0.014779582307969177
|
Dockerfile
CHANGED
|
@@ -17,6 +17,7 @@ RUN pip install --no-cache-dir --upgrade pip && \
|
|
| 17 |
# Copier le code de l'application
|
| 18 |
COPY --chown=user api.py .
|
| 19 |
COPY --chown=user 2_Data_transformed/app_train_Enc_wo_Outliers_Feat_Eng_Join_Align_head.csv ./2_Data_transformed/
|
|
|
|
| 20 |
COPY --chown=user 3_Results/best_gradient_boosting_model.pkl ./3_Results/
|
| 21 |
|
| 22 |
# ============================================
|
|
|
|
| 17 |
# Copier le code de l'application
|
| 18 |
COPY --chown=user api.py .
|
| 19 |
COPY --chown=user 2_Data_transformed/app_train_Enc_wo_Outliers_Feat_Eng_Join_Align_head.csv ./2_Data_transformed/
|
| 20 |
+
COPY --chown=user 2_Data_transformed/shap_feature_importance.csv ./2_Data_transformed/
|
| 21 |
COPY --chown=user 3_Results/best_gradient_boosting_model.pkl ./3_Results/
|
| 22 |
|
| 23 |
# ============================================
|
api.py
CHANGED
|
@@ -59,7 +59,7 @@ try:
|
|
| 59 |
except PermissionError:
|
| 60 |
pass # Ignorer si on ne peut pas écrire le fichier de log
|
| 61 |
|
| 62 |
-
# Handler flux (stdout) pour permettre l'affichage dans la console
|
| 63 |
stream_handler = logging.StreamHandler()
|
| 64 |
stream_handler.setFormatter(json_formatter)
|
| 65 |
logger.addHandler(stream_handler)
|
|
@@ -68,8 +68,8 @@ logger.addHandler(stream_handler)
|
|
| 68 |
#2-------------------------Initialisation de l'API et définition des variables globales--------------------
|
| 69 |
# Initialisation de l'application FastAPI
|
| 70 |
app = FastAPI(
|
| 71 |
-
title="API de
|
| 72 |
-
description="API pour
|
| 73 |
version="1.0.0"
|
| 74 |
)
|
| 75 |
|
|
@@ -79,8 +79,11 @@ BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
|
| 79 |
# Chemin vers le fichier du modèle pickle (modèle entraîné)
|
| 80 |
MODEL_PATH = os.path.join(BASE_DIR, "3_Results/best_gradient_boosting_model.pkl")
|
| 81 |
|
| 82 |
-
# Chemin vers le fichier CSV pour récupérer l'ordre
|
| 83 |
-
|
|
|
|
|
|
|
|
|
|
| 84 |
|
| 85 |
# Chemin vers le fichier CSV pour enregistrer les données (détection de data drift)
|
| 86 |
# Sur HF Spaces, utiliser /tmp pour les fichiers temporaires (écriture autorisée)
|
|
@@ -152,11 +155,11 @@ def load_column_order() -> List[str]:
|
|
| 152 |
"""
|
| 153 |
try:
|
| 154 |
# Charger uniquement les en-têtes du CSV (nrows=0) pour récupérer les colonnes
|
| 155 |
-
df = pd.read_csv(
|
| 156 |
-
logger.info(f"Nombre et ordre des colonnes chargé depuis {
|
| 157 |
except FileNotFoundError:
|
| 158 |
# Fichier absent -> on ne peut pas connaitre l'ordre des colonnes
|
| 159 |
-
logger.error(f"Fichier CSV non trouvé: {
|
| 160 |
return []
|
| 161 |
try:
|
| 162 |
# Supprimer des colonnes id or target si elles existent avant de retourner l'ordre
|
|
@@ -168,12 +171,33 @@ def load_column_order() -> List[str]:
|
|
| 168 |
# Retourner la liste des noms de colonnes
|
| 169 |
return df.columns.tolist()
|
| 170 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 171 |
# Chargement du modèle au démarrage de l'application
|
| 172 |
model = load_model()
|
| 173 |
|
| 174 |
# Chargement de l'ordre des colonnes au démarrage
|
| 175 |
column_order = load_column_order()
|
| 176 |
|
|
|
|
|
|
|
|
|
|
| 177 |
logger.info("API initialisée et prête")
|
| 178 |
|
| 179 |
#4-------------------------Définition des modèles de données Pydantic pour les entrées et sorties de l'API, et implémentation des endpoints--------------------
|
|
@@ -228,6 +252,19 @@ def predict(input_data: PredictionInput):
|
|
| 228 |
logger.error("Ordre des colonnes non disponible")
|
| 229 |
raise HTTPException(status_code=500, detail="Ordre des colonnes non chargé")
|
| 230 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
try:
|
| 232 |
# R��ordonner les features selon l'ordre des colonnes du CSV
|
| 233 |
# Si une feature manque, on met np.nan pour conserver la structure
|
|
|
|
| 59 |
except PermissionError:
|
| 60 |
pass # Ignorer si on ne peut pas écrire le fichier de log
|
| 61 |
|
| 62 |
+
# Handler flux (stdout) pour permettre l'affichage dans la console/terminal et rattachement au logger
|
| 63 |
stream_handler = logging.StreamHandler()
|
| 64 |
stream_handler.setFormatter(json_formatter)
|
| 65 |
logger.addHandler(stream_handler)
|
|
|
|
| 68 |
#2-------------------------Initialisation de l'API et définition des variables globales--------------------
|
| 69 |
# Initialisation de l'application FastAPI
|
| 70 |
app = FastAPI(
|
| 71 |
+
title="API de Classification binaire du Risque de Crédit",
|
| 72 |
+
description="API pour classifier les demandes de crédit en fonction du risque de défaut, avec un seuil métier optimisé pour le métier",
|
| 73 |
version="1.0.0"
|
| 74 |
)
|
| 75 |
|
|
|
|
| 79 |
# Chemin vers le fichier du modèle pickle (modèle entraîné)
|
| 80 |
MODEL_PATH = os.path.join(BASE_DIR, "3_Results/best_gradient_boosting_model.pkl")
|
| 81 |
|
| 82 |
+
# Chemin vers le fichier CSV pour récupérer l'ordre de toutes les colonnes nécessaires au modèle
|
| 83 |
+
COLS_PATH = os.path.join(BASE_DIR, "2_Data_transformed/app_train_Enc_wo_Outliers_Feat_Eng_Join_Align_head.csv")
|
| 84 |
+
|
| 85 |
+
#Chemin vers le fichier CSV pour récupérer les variables obligatoires pour faire une prédiction assez fiable
|
| 86 |
+
FEAT_PATH = os.path.join(BASE_DIR, "2_Data_transformed/shap_feature_importance.csv")
|
| 87 |
|
| 88 |
# Chemin vers le fichier CSV pour enregistrer les données (détection de data drift)
|
| 89 |
# Sur HF Spaces, utiliser /tmp pour les fichiers temporaires (écriture autorisée)
|
|
|
|
| 155 |
"""
|
| 156 |
try:
|
| 157 |
# Charger uniquement les en-têtes du CSV (nrows=0) pour récupérer les colonnes
|
| 158 |
+
df = pd.read_csv(COLS_PATH, nrows=0, sep=';') # Charger uniquement les en-têtes
|
| 159 |
+
logger.info(f"Nombre et ordre des colonnes chargé depuis {COLS_PATH}")
|
| 160 |
except FileNotFoundError:
|
| 161 |
# Fichier absent -> on ne peut pas connaitre l'ordre des colonnes
|
| 162 |
+
logger.error(f"Fichier CSV non trouvé: {COLS_PATH}")
|
| 163 |
return []
|
| 164 |
try:
|
| 165 |
# Supprimer des colonnes id or target si elles existent avant de retourner l'ordre
|
|
|
|
| 171 |
# Retourner la liste des noms de colonnes
|
| 172 |
return df.columns.tolist()
|
| 173 |
|
| 174 |
+
|
| 175 |
+
def load_important_features() -> List[str]:
|
| 176 |
+
"""
|
| 177 |
+
Charge le fichier CSV des importances de features et retourne la liste des features importantes.
|
| 178 |
+
|
| 179 |
+
Returns:
|
| 180 |
+
Liste des noms de features importantes.
|
| 181 |
+
"""
|
| 182 |
+
try:
|
| 183 |
+
df = pd.read_csv(FEAT_PATH, sep=';')
|
| 184 |
+
logger.info(f"Fichier d'importance des features chargé depuis {FEAT_PATH}")
|
| 185 |
+
important_features = df['Feature'].tolist()
|
| 186 |
+
logger.info(f"Nombre de features importantes chargées: {len(important_features)}")
|
| 187 |
+
return important_features
|
| 188 |
+
except FileNotFoundError:
|
| 189 |
+
logger.error(f"Fichier d'importance des features non trouvé: {FEAT_PATH}")
|
| 190 |
+
return []
|
| 191 |
+
|
| 192 |
# Chargement du modèle au démarrage de l'application
|
| 193 |
model = load_model()
|
| 194 |
|
| 195 |
# Chargement de l'ordre des colonnes au démarrage
|
| 196 |
column_order = load_column_order()
|
| 197 |
|
| 198 |
+
# Chargement de la liste des features importantes
|
| 199 |
+
important_features = load_important_features()
|
| 200 |
+
|
| 201 |
logger.info("API initialisée et prête")
|
| 202 |
|
| 203 |
#4-------------------------Définition des modèles de données Pydantic pour les entrées et sorties de l'API, et implémentation des endpoints--------------------
|
|
|
|
| 252 |
logger.error("Ordre des colonnes non disponible")
|
| 253 |
raise HTTPException(status_code=500, detail="Ordre des colonnes non chargé")
|
| 254 |
|
| 255 |
+
if not important_features:
|
| 256 |
+
logger.error("Liste des features importantes non disponible")
|
| 257 |
+
raise HTTPException(status_code=500, detail="Liste des features importantes non chargée")
|
| 258 |
+
|
| 259 |
+
#Vérifier que les features importantes sont présentes dans les données d'entrée sinon lever une exception
|
| 260 |
+
missing_important_features = [feat for feat in important_features if feat not in input_data.features]
|
| 261 |
+
if missing_important_features:
|
| 262 |
+
logger.error("Features importantes manquantes: " + ", ".join(missing_important_features))
|
| 263 |
+
raise HTTPException(
|
| 264 |
+
status_code=400,
|
| 265 |
+
detail=f"Features importantes manquantes: {missing_important_features}"
|
| 266 |
+
)
|
| 267 |
+
|
| 268 |
try:
|
| 269 |
# R��ordonner les features selon l'ordre des colonnes du CSV
|
| 270 |
# Si une feature manque, on met np.nan pour conserver la structure
|