CoolFace
Apppublic

lcamara/deployMLModel

sourceHugging Faceupdated 5mo agoView on Hugging Face
0likes
preprocessing.py209 linesDownload Raw Back to app
1"""Preprocessing pipeline — reproduces the P4 notebook's prepare_features + encode_features."""2 3import pandas as pd4 5 6def load_and_merge(sirh_path: str, eval_path: str, sondage_path: str) -> pd.DataFrame:7    """Load the 3 CSV files and merge them on id_employee."""8    sirh = pd.read_csv(sirh_path)9    evaluation = pd.read_csv(eval_path)10    sondage = pd.read_csv(sondage_path)11 12    # Clean evaluation13    evaluation["augementation_salaire_precedente"] = (14        evaluation["augementation_salaire_precedente"]15        .str.replace(" %", "", regex=False)16        .astype(float)17    )18    evaluation["id_employee"] = evaluation["eval_number"].apply(lambda x: int(x.replace("E_", "")))19    evaluation = evaluation.drop(columns=["eval_number"])20 21    # Clean sondage22    sondage = sondage.rename(columns={"code_sondage": "id_employee"})23 24    # Drop constant columns25    sirh = sirh.drop(columns=["nombre_heures_travailless"], errors="ignore")26    sondage = sondage.drop(27        columns=["ayant_enfants", "nombre_employee_sous_responsabilite"], errors="ignore"28    )29 30    # Merge31    df = sirh.merge(evaluation, on="id_employee").merge(sondage, on="id_employee")32    return df33 34 35def prepare_features(df: pd.DataFrame) -> tuple[pd.DataFrame, pd.Series]:36    """Feature engineering + drop columns. Returns (X, y)."""37    df = df.copy()38 39    # Target40    y = df["a_quitte_l_entreprise"].map({"Oui": 1, "Non": 0})41 42    # Engineered features43    df["ratio_anciennete_experience"] = df.apply(44        lambda r: (45            r["annees_dans_l_entreprise"] / r["annee_experience_totale"]46            if r["annee_experience_totale"] != 047            else 048        ),49        axis=1,50    )51    df["satisfaction_moyenne"] = df[52        [53            "satisfaction_employee_environnement",54            "satisfaction_employee_nature_travail",55            "satisfaction_employee_equipe",56            "satisfaction_employee_equilibre_pro_perso",57        ]58    ].mean(axis=1)59    df["ecart_evaluation"] = df["note_evaluation_actuelle"] - df["note_evaluation_precedente"]60    df["anciennete_sans_promotion"] = (61        df["annees_dans_l_entreprise"] - df["annees_depuis_la_derniere_promotion"]62    )63 64    # Drop columns65    cols_to_drop = [66        "a_quitte_l_entreprise",67        "id_employee",68        "niveau_hierarchique_poste",69        "note_evaluation_precedente",70        "annes_sous_responsable_actuel",71        "annees_dans_le_poste_actuel",72    ]73    X = df.drop(columns=cols_to_drop, errors="ignore")74    return X, y75 76 77def encode_features(X: pd.DataFrame) -> pd.DataFrame:78    """Encode categorical features — same logic as notebook."""79    X = X.copy()80 81    # Binary mappings82    X["genre"] = X["genre"].map({"F": 0, "M": 1})83    X["heure_supplementaires"] = X["heure_supplementaires"].map({"Non": 0, "Oui": 1})84 85    # Ordinal mapping86    X["frequence_deplacement"] = X["frequence_deplacement"].map(87        {"Aucun": 0, "Occasionnel": 1, "Frequent": 2}88    )89 90    # One-hot encoding91    X = pd.get_dummies(X, drop_first=True, dtype=int)92    return X93 94 95# Exact feature order the trained model expects (40 features)96EXPECTED_FEATURES = [97    "age",98    "genre",99    "revenu_mensuel",100    "nombre_experiences_precedentes",101    "annee_experience_totale",102    "annees_dans_l_entreprise",103    "satisfaction_employee_environnement",104    "satisfaction_employee_nature_travail",105    "satisfaction_employee_equipe",106    "satisfaction_employee_equilibre_pro_perso",107    "note_evaluation_actuelle",108    "heure_supplementaires",109    "augementation_salaire_precedente",110    "nombre_participation_pee",111    "nb_formations_suivies",112    "distance_domicile_travail",113    "niveau_education",114    "frequence_deplacement",115    "annees_depuis_la_derniere_promotion",116    "ratio_anciennete_experience",117    "satisfaction_moyenne",118    "ecart_evaluation",119    "anciennete_sans_promotion",120    "statut_marital_Divorcé(e)",121    "statut_marital_Marié(e)",122    "departement_Consulting",123    "departement_Ressources Humaines",124    "poste_Cadre Commercial",125    "poste_Consultant",126    "poste_Directeur Technique",127    "poste_Manager",128    "poste_Représentant Commercial",129    "poste_Ressources Humaines",130    "poste_Senior Manager",131    "poste_Tech Lead",132    "domaine_etude_Entrepreunariat",133    "domaine_etude_Infra & Cloud",134    "domaine_etude_Marketing",135    "domaine_etude_Ressources Humaines",136    "domaine_etude_Transformation Digitale",137]138 139 140def preprocess_single(data: dict) -> pd.DataFrame:141    """Preprocess a single prediction input (dict of raw features) into model-ready DataFrame.142 143    Accepts raw human-readable values and returns a 1-row DataFrame with all 40 encoded features.144    """145    row = pd.DataFrame([data])146 147    # Binary + ordinal encoding148    row["genre"] = row["genre"].map({"F": 0, "M": 1})149    row["heure_supplementaires"] = row["heure_supplementaires"].map({"Non": 0, "Oui": 1})150    row["frequence_deplacement"] = row["frequence_deplacement"].map(151        {"Aucun": 0, "Occasionnel": 1, "Frequent": 2}152    )153 154    # Engineered features155    row["ratio_anciennete_experience"] = row.apply(156        lambda r: (157            r["annees_dans_l_entreprise"] / r["annee_experience_totale"]158            if r["annee_experience_totale"] != 0159            else 0160        ),161        axis=1,162    )163    row["satisfaction_moyenne"] = row[164        [165            "satisfaction_employee_environnement",166            "satisfaction_employee_nature_travail",167            "satisfaction_employee_equipe",168            "satisfaction_employee_equilibre_pro_perso",169        ]170    ].mean(axis=1)171    row["ecart_evaluation"] = row["note_evaluation_actuelle"] - row["note_evaluation_precedente"]172    row["anciennete_sans_promotion"] = (173        row["annees_dans_l_entreprise"] - row["annees_depuis_la_derniere_promotion"]174    )175 176    # One-hot columns — create all expected columns with 0, then set relevant ones to 1177    for col in EXPECTED_FEATURES:178        if col not in row.columns:179            row[col] = 0180 181    # Set one-hot flags from categorical inputs182    categorical_mappings = {183        "statut_marital": "statut_marital_",184        "departement": "departement_",185        "poste": "poste_",186        "domaine_etude": "domaine_etude_",187    }188    for cat_col, prefix in categorical_mappings.items():189        if cat_col in row.columns:190            value = row[cat_col].iloc[0]191            dummy_col = f"{prefix}{value}"192            if dummy_col in EXPECTED_FEATURES:193                row[dummy_col] = 1194            row = row.drop(columns=[cat_col])195 196    # Drop columns not needed for prediction197    cols_to_drop = [198        "id_employee",199        "niveau_hierarchique_poste",200        "note_evaluation_precedente",201        "annes_sous_responsable_actuel",202        "annees_dans_le_poste_actuel",203    ]204    row = row.drop(columns=[c for c in cols_to_drop if c in row.columns])205 206    # Reorder to match training order, fill any missing with 0207    row = row.reindex(columns=EXPECTED_FEATURES, fill_value=0)208    return row209