sma-nas/credit-scoring-api
0
1"""2Module de traitement et préparation des données pour le scoring de crédit.3"""4 5import pandas as pd6import numpy as np7from sklearn.preprocessing import LabelEncoder, StandardScaler8from sklearn.impute import SimpleImputer9import warnings10warnings.filterwarnings('ignore')11 12 13def load_data(file_path):14 """15 Charge un fichier de données.16 17 Args:18 file_path (str): Chemin vers le fichier19 20 Returns:21 pd.DataFrame: Données chargées22 """23 try:24 if file_path.endswith('.csv'):25 return pd.read_csv(file_path)26 elif file_path.endswith('.xlsx'):27 return pd.read_excel(file_path)28 else:29 raise ValueError("Format de fichier non supporté. Utiliser .csv ou .xlsx")30 except Exception as e:31 print(f"Erreur lors du chargement : {e}")32 return None33 34 35def explore_data(df, name="Dataset"):36 """37 Affiche un résumé exploratoire du dataset.38 39 Args:40 df (pd.DataFrame): Dataset à explorer41 name (str): Nom du dataset42 """43 print(f"\n{'='*60}")44 print(f"Exploration : {name}")45 print(f"{'='*60}")46 print(f"\nDimensions : {df.shape[0]} lignes x {df.shape[1]} colonnes")47 print(f"\nTypes de colonnes :")48 print(df.dtypes.value_counts())49 print(f"\nValeurs manquantes :")50 missing = df.isnull().sum()51 if missing.sum() > 0:52 missing_pct = (missing / len(df)) * 10053 missing_df = pd.DataFrame({54 'Colonnes': missing.index,55 'Manquants': missing.values,56 'Pourcentage': missing_pct.values57 })58 print(missing_df[missing_df['Manquants'] > 0].sort_values('Manquants', ascending=False))59 else:60 print("Aucune valeur manquante")61 print(f"\nDoublons : {df.duplicated().sum()}")62 63 64def check_duplicates(df):65 """66 Vérifie et supprime les doublons.67 68 Args:69 df (pd.DataFrame): Dataset70 71 Returns:72 pd.DataFrame: Dataset sans doublons73 """74 n_duplicates = df.duplicated().sum()75 if n_duplicates > 0:76 print(f"⚠️ {n_duplicates} doublons trouvés et supprimés")77 return df.drop_duplicates()78 print("✓ Aucun doublon trouvé")79 return df80 81 82def merge_datasets(df_list, keys, how='inner'):83 """84 Fusionne plusieurs datasets.85 86 Args:87 df_list (list): Liste de DataFrames88 keys (list): Liste des clés de fusion89 how (str): Type de jointure90 91 Returns:92 pd.DataFrame: Dataset fusionné93 """94 if len(df_list) < 2:95 return df_list[0] if df_list else None96 97 result = df_list[0]98 for i, df in enumerate(df_list[1:], 1):99 before = len(result)100 result = result.merge(df, on=keys[i-1] if isinstance(keys, list) else keys, how=how)101 after = len(result)102 print(f"Fusion {i}: {before} lignes → {after} lignes")103 104 return result105 106 107def handle_missing_values(df, strategy='auto', threshold=0.5):108 """109 Gère les valeurs manquantes avec différentes stratégies.110 111 Args:112 df (pd.DataFrame): Dataset113 strategy (str): Stratégie ('auto', 'drop', 'mean', 'median', 'mode')114 threshold (float): Seuil de suppression de colonnes (% de valeurs manquantes)115 116 Returns:117 pd.DataFrame: Dataset avec valeurs manquantes traitées118 """119 df_clean = df.copy()120 121 # Colonnes avec trop de valeurs manquantes122 missing_pct = df_clean.isnull().sum() / len(df_clean)123 cols_to_drop = missing_pct[missing_pct > threshold].index.tolist()124 125 if cols_to_drop:126 print(f"⚠️ Suppression de {len(cols_to_drop)} colonnes avec >{threshold*100}% de valeurs manquantes:")127 print(cols_to_drop)128 df_clean = df_clean.drop(columns=cols_to_drop)129 130 # Imputation pour les colonnes restantes131 if strategy == 'auto':132 # Colonnes numériques : médiane133 numeric_cols = df_clean.select_dtypes(include=[np.number]).columns134 if len(numeric_cols) > 0:135 imputer_num = SimpleImputer(strategy='median')136 df_clean[numeric_cols] = imputer_num.fit_transform(df_clean[numeric_cols])137 138 # Colonnes catégorielles : mode139 cat_cols = df_clean.select_dtypes(include=['object', 'category']).columns140 if len(cat_cols) > 0:141 imputer_cat = SimpleImputer(strategy='most_frequent')142 df_clean[cat_cols] = imputer_cat.fit_transform(df_clean[cat_cols])143 144 print(f"✓ Valeurs manquantes traitées. Colonnes restantes : {df_clean.shape[1]}")145 return df_clean146 147 148def encode_categorical(df, method='label', target_col=None):149 """150 Encode les variables catégorielles.151 152 Args:153 df (pd.DataFrame): Dataset154 method (str): Méthode d'encodage ('label', 'onehot')155 target_col (str): Colonne cible à ne pas encoder156 157 Returns:158 pd.DataFrame: Dataset avec variables encodées159 """160 df_encoded = df.copy()161 cat_cols = df_encoded.select_dtypes(include=['object', 'category']).columns.tolist()162 163 if target_col and target_col in cat_cols:164 cat_cols.remove(target_col)165 166 if method == 'label':167 for col in cat_cols:168 le = LabelEncoder()169 df_encoded[col] = le.fit_transform(df_encoded[col].astype(str))170 print(f"✓ {len(cat_cols)} colonnes encodées (Label Encoding)")171 172 elif method == 'onehot':173 df_encoded = pd.get_dummies(df_encoded, columns=cat_cols, drop_first=True)174 print(f"✓ {len(cat_cols)} colonnes encodées (One-Hot Encoding)")175 176 return df_encoded177 178 179def create_features(df):180 """181 Crée de nouvelles features à partir des variables existantes.182 183 Args:184 df (pd.DataFrame): Dataset185 186 Returns:187 pd.DataFrame: Dataset avec nouvelles features188 """189 df_features = df.copy()190 191 # Exemple : ajouter des features de date si présentes192 date_cols = df_features.select_dtypes(include=['datetime64']).columns193 for col in date_cols:194 df_features[f'{col}_year'] = df_features[col].dt.year195 df_features[f'{col}_month'] = df_features[col].dt.month196 df_features[f'{col}_dayofweek'] = df_features[col].dt.dayofweek197 198 print(f"✓ Features créées. Nouvelles dimensions : {df_features.shape}")199 return df_features200 201 202def scale_features(df, target_col=None):203 """204 Normalise les features numériques.205 206 Args:207 df (pd.DataFrame): Dataset208 target_col (str): Colonne cible à ne pas normaliser209 210 Returns:211 pd.DataFrame: Dataset avec features normalisées212 StandardScaler: Scaler ajusté213 """214 df_scaled = df.copy()215 numeric_cols = df_scaled.select_dtypes(include=[np.number]).columns.tolist()216 217 if target_col and target_col in numeric_cols:218 numeric_cols.remove(target_col)219 220 if len(numeric_cols) > 0:221 scaler = StandardScaler()222 df_scaled[numeric_cols] = scaler.fit_transform(df_scaled[numeric_cols])223 print(f"✓ {len(numeric_cols)} features numériques normalisées")224 return df_scaled, scaler225 226 return df_scaled, None227 228 229def save_processed_data(df, file_path):230 """231 Sauvegarde les données préparées.232 233 Args:234 df (pd.DataFrame): Dataset à sauvegarder235 file_path (str): Chemin de sauvegarde236 """237 try:238 df.to_csv(file_path, index=False)239 print(f"✓ Données sauvegardées : {file_path}")240 except Exception as e:241 print(f"❌ Erreur lors de la sauvegarde : {e}")242 