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 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 Prédiction ML",
72
- description="API pour effectuer des prédictions avec un modèle de Machine Learning",
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 des colonnes
83
- CSV_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 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(CSV_PATH, nrows=0, sep=';') # Charger uniquement les en-têtes
156
- logger.info(f"Nombre et ordre des colonnes chargé depuis {CSV_PATH}")
157
  except FileNotFoundError:
158
  # Fichier absent -> on ne peut pas connaitre l'ordre des colonnes
159
- logger.error(f"Fichier CSV non trouvé: {CSV_PATH}")
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