import pandas as pd import numpy as np from sklearn.experimental import enable_iterative_imputer from sklearn.impute import IterativeImputer, SimpleImputer from sklearn.preprocessing import RobustScaler, LabelEncoder import joblib import os # Configuration os.makedirs('processed', exist_ok=True) os.makedirs('artifacts', exist_ok=True) def preprocess_data(file_path): print(f"Chargement du dataset : {file_path}") df = pd.read_csv(file_path) # --- 1. Nettoyage Initial --- target_col = "Stage de l'IRC" if target_col in df.columns: df = df[df[target_col] != "0%"] # Bruit sémantique df['Situation Matrimoniale'] = df['Situation Matrimoniale'].astype(str).replace({'Veuf': 'Veuf(ve)', '38%': np.nan}) df['Etat Général (EG) à l\'Admission'] = df['Etat Général (EG) à l\'Admission'].astype(str).replace({'Aceptable': 'Acceptable', '4%': np.nan}) df['Conscience'] = df['Conscience'].astype(str).replace({'38%': np.nan}) # Conversion numérique robuste for col in df.columns: if col == target_col or col == "ID": continue temp = df[col].astype(str).str.replace(',', '.').str.extract(r'([-+]?\d*\.?\d+)')[0] converted = pd.to_numeric(temp, errors='coerce') if converted.notnull().sum() > 0.15 * len(df): df[col] = converted # --- 2. Feature Engineering Clinique --- print("\n--- Feature Engineering Clinique ---") if 'Créatinine (mg/L)' in df.columns: df['Creat_mg_dL'] = df['Créatinine (mg/L)'] / 10.0 if 'Urée (g/L)' in df.columns: df['Urea_mg_dL'] = df['Urée (g/L)'] * 100.0 # Ratio Urée / Créatinine if 'Urea_mg_dL' in df.columns and 'Creat_mg_dL' in df.columns: df['Ratio_Urea_Creat'] = df['Urea_mg_dL'] / (df['Creat_mg_dL'].replace(0, np.nan)) df['Ratio_Urea_Creat'] = df['Ratio_Urea_Creat'].replace([np.inf, -np.inf], np.nan) # eGFR (MDRD) if 'Creat_mg_dL' in df.columns and 'Age' in df.columns and 'Sexe' in df.columns: gender_mult = df['Sexe'].astype(str).str.lower().apply(lambda x: 0.742 if 'f' in x else 1.0) # Avoid division by zero/negatives for power safe_creat = df['Creat_mg_dL'].clip(lower=0.1) safe_age = df['Age'].clip(lower=1) df['eGFR_MDRD'] = 175 * (safe_creat**-1.154) * (safe_age**-0.203) * gender_mult print("Features cliniques (eGFR, Ratio U/C) calculées.") # --- 3. Suppression Leakage --- leak_terms = ["Causes Majeure après Diagnostic", "Evolution de l'Etat Générale", "Diagnostic final"] cols_to_drop_leak = [c for c in df.columns if any(term in c for term in leak_terms)] df = df.drop(columns=cols_to_drop_leak) # --- 4. Encodage Ordinal --- ordinal_mappings = { 'Hygiène buccodentaire': {'Mauvaise': 0, 'Insuffisante': 1, 'Acceptable': 2, 'Bonne': 3}, 'Conscience': {'Coma': 0, 'Obnubilé': 1, 'Somnolence': 2, 'Claire': 3}, 'Etat Général (EG) à l\'Admission': {'Altéré': 0, 'Urémique': 1, 'Acceptable': 2, 'Bon': 3} } for col, mapping in ordinal_mappings.items(): if col in df.columns: df[col] = df[col].map(mapping) # --- 5. Imputation & Scaling --- all_null_cols = df.columns[df.isnull().all()] df = df.drop(columns=all_null_cols) num_cols = df.select_dtypes(include=['number']).columns.tolist() cat_cols = df.select_dtypes(include=['object']).columns.tolist() if target_col in cat_cols: cat_cols.remove(target_col) if "ID" in cat_cols: cat_cols.remove("ID") if num_cols: mice_imputer = IterativeImputer(random_state=42, max_iter=10) df[num_cols] = mice_imputer.fit_transform(df[num_cols]) joblib.dump(mice_imputer, 'artifacts/mice_imputer.joblib') if cat_cols: cat_imputer = SimpleImputer(strategy='most_frequent') df[cat_cols] = cat_imputer.fit_transform(df[cat_cols]) joblib.dump(cat_imputer, 'artifacts/cat_imputer.joblib') # Encodage Cible le = LabelEncoder() df[target_col] = le.fit_transform(df[target_col]) joblib.dump(le, 'artifacts/target_encoder.joblib') # One-Hot Encoding df = pd.get_dummies(df, columns=cat_cols, drop_first=True) # Robust Scaling scaler = RobustScaler() features = df.drop(columns=[target_col, 'ID'], errors='ignore') # Nettoyage des noms de colonnes pour XGBoost (Pas de [, ], <) import re features.columns = [re.sub(r'[\[\]<]', '_', str(col)) for col in features.columns] scaled_features = scaler.fit_transform(features) joblib.dump(scaler, 'artifacts/scaler.joblib') # Export df_final = pd.DataFrame(scaled_features, columns=features.columns) df_final[target_col] = df[target_col].values df_final.to_csv('processed/ckd_processed.csv', index=False) print(f"Dataset final généré : {df_final.shape}") if __name__ == "__main__": preprocess_data('../ckd_dataset.csv')