#!/usr/bin/env python3 """ Générateur de données de test pour détecter les outliers UNIVARIÉS et MULTIVARIÉS. Ce script crée un dataset avec : 1. Des outliers univariés évidents (valeurs extrêmes dans une seule colonne) 2. Des outliers multivariés (combinaisons de valeurs normales individuellement mais anormales ensemble) 3. Des données normales pour la majorité """ import pandas as pd import numpy as np from pathlib import Path # Configuration np.random.seed(42) N_NORMAL = 100 # Nombre de lignes normales def generate_outlier_dataset(): """ Génère un dataset avec des outliers contrôlés pour tester les deux types de détection. """ data = [] # ======================================================================== # 1. DONNÉES NORMALES (baseline) # ======================================================================== print("📊 Génération des données normales...") for i in range(N_NORMAL): data.append({ "ID": i + 1, "Age": np.random.normal(40, 10), # Moyenne 40, écart-type 10 "Salaire": np.random.normal(35000, 8000), # Moyenne 35k, écart-type 8k "Experience": np.random.normal(10, 4), # Moyenne 10 ans, écart-type 4 "Performance": np.random.normal(75, 10), # Moyenne 75/100, écart-type 10 "Heures_Sup": np.random.normal(5, 3), # Moyenne 5h/mois, écart-type 3 "Type": "Normal" }) # ======================================================================== # 2. OUTLIERS UNIVARIÉS (évidents dans UNE colonne) # ======================================================================== print("🔴 Génération des outliers univariés...") # Outlier 1: Âge extrême (150 ans - impossible) data.append({ "ID": 101, "Age": 150, "Salaire": 38000, "Experience": 12, "Performance": 78, "Heures_Sup": 6, "Type": "Outlier_Uni_Age" }) # Outlier 2: Salaire extrêmement élevé (500k - 10x la normale) data.append({ "ID": 102, "Age": 45, "Salaire": 500000, "Experience": 15, "Performance": 82, "Heures_Sup": 8, "Type": "Outlier_Uni_Salaire" }) # Outlier 3: Salaire négatif (impossible) data.append({ "ID": 103, "Age": 35, "Salaire": -5000, "Experience": 8, "Performance": 72, "Heures_Sup": 4, "Type": "Outlier_Uni_Salaire_Neg" }) # Outlier 4: Performance > 100 (impossible) data.append({ "ID": 104, "Age": 38, "Salaire": 42000, "Experience": 11, "Performance": 150, "Heures_Sup": 7, "Type": "Outlier_Uni_Perf" }) # Outlier 5: Heures supplémentaires négatives data.append({ "ID": 105, "Age": 42, "Salaire": 36000, "Experience": 13, "Performance": 76, "Heures_Sup": -20, "Type": "Outlier_Uni_Heures" }) # ======================================================================== # 3. OUTLIERS MULTIVARIÉS (normaux individuellement, anormaux ensemble) # ======================================================================== print("🟣 Génération des outliers multivariés...") # Outlier Multivarié 1: Jeune avec BEAUCUP d'expérience (impossible) # Age=25 (normal) mais Experience=30 (impossible pour cet âge) data.append({ "ID": 201, "Age": 25, "Salaire": 32000, "Experience": 30, "Performance": 70, "Heures_Sup": 5, "Type": "Outlier_Multi_Age_Exp" }) # Outlier Multivarié 2: Haut salaire avec basse performance (suspect) # Salaire=80k (normal possible) mais Performance=40 (anormalement bas pour ce salaire) data.append({ "ID": 202, "Age": 45, "Salaire": 80000, "Experience": 15, "Performance": 40, "Heures_Sup": 2, "Type": "Outlier_Multi_Salaire_Perf" }) # Outlier Multivarié 3: Faible expérience avec très haut salaire (suspect) data.append({ "ID": 203, "Age": 28, "Salaire": 95000, "Experience": 1, "Performance": 85, "Heures_Sup": 15, "Type": "Outlier_Multi_Exp_Salaire" }) # Outlier Multivarié 4: Personne âgée avec junior-level tout data.append({ "ID": 204, "Age": 65, "Salaire": 25000, "Experience": 1, "Performance": 60, "Heures_Sup": 0, "Type": "Outlier_Multi_Senior_Junior" }) # Outlier Multivarié 5: Performance parfaite avec 0 heures supp (rare) data.append({ "ID": 205, "Age": 35, "Salaire": 40000, "Experience": 10, "Performance": 100, "Heures_Sup": 0, "Type": "Outlier_Multi_Perf_Heures" }) # Outlier Multivarié 6: Combinaison impossible - Junior avec salaire senior ET perf max data.append({ "ID": 206, "Age": 22, "Salaire": 85000, "Experience": 0, "Performance": 95, "Heures_Sup": 0, "Type": "Outlier_Multi_Impossible" }) # ======================================================================== # 4. CAS LIMITES (valeurs frontières) # ======================================================================== print("🎯 Génération des cas limites...") # Cas limite 1: Zéro partout (suspect mais pas impossible) data.append({ "ID": 301, "Age": 22, "Salaire": 0, "Experience": 0, "Performance": 0, "Heures_Sup": 0, "Type": "Cas_Limie_Zeros" }) # Cas limite 2: Très âgé avec beaucoup d'expérience (normal) data.append({ "ID": 302, "Age": 62, "Salaire": 70000, "Experience": 40, "Performance": 88, "Heures_Sup": 3, "Type": "Normal_Senior" }) # Cas limite 3: Salaire minimum légal (normal) data.append({ "ID": 303, "Age": 25, "Salaire": 15000, "Experience": 2, "Performance": 65, "Heures_Sup": 2, "Type": "Normal_Salaire_Min" }) # Création du DataFrame df = pd.DataFrame(data) # Arrondir les valeurs numériques pour plus de clarté numeric_cols = ["Age", "Salaire", "Experience", "Performance", "Heures_Sup"] for col in numeric_cols: df[col] = df[col].round(2) # Réordonner les colonnes df = df[["ID", "Age", "Experience", "Salaire", "Performance", "Heures_Sup", "Type"]] return df def main(): print("=" * 70) print("🧪 GÉNÉRATEUR DE DONNÉES DE TEST - OUTLIERS UNIVARIÉS & MULTIVARIÉS") print("=" * 70) print() # Générer le dataset df = generate_outlier_dataset() # Sauvegarder en CSV output_dir = Path("/home/sepehr/dev/Data_analysis/backend/test_data") output_dir.mkdir(exist_ok=True) csv_path = output_dir / "test_outliers_complete.csv" df.to_csv(csv_path, index=False) excel_path = output_dir / "test_outliers_complete.xlsx" df.to_excel(excel_path, index=False) # Afficher les statistiques print() print("=" * 70) print("📊 STATISTIQUES DU DATASET") print("=" * 70) print(f"✅ Total lignes : {len(df)}") print(f"📈 Colonnes : {len(df.columns)}") print() print("🔴 Outliers univariés attendus : 5") print(" - ID 101: Âge = 150 ans") print(" - ID 102: Salaire = 500,000€") print(" - ID 103: Salaire = -5,000€ (négatif)") print(" - ID 104: Performance = 150 (>100)") print(" - ID 105: Heures_Sup = -20 (négatif)") print() print("🟣 Outliers multivariés attendus : 6") print(" - ID 201: Âge=25 avec Exp=30 (impossible)") print(" - ID 202: Salaire=80k avec Perf=40 (incohérent)") print(" - ID 203: Exp=1 avec Salaire=95k (suspect)") print(" - ID 204: Âge=65 avec Exp=1 (incohérent)") print(" - ID 205: Perf=100 avec Heures_Sup=0 (rare)") print(" - ID 206: Âge=22, Exp=0, Salaire=85k (impossible)") print() print("=" * 70) print("💾 FICHIERS GÉNÉRÉS") print("=" * 70) print(f"📄 CSV : {csv_path}") print(f"📊 Excel : {excel_path}") print() print("=" * 70) print("🎯 COMMENT TESTER") print("=" * 70) print("1. Importez le fichier 'test_outliers_complete.csv' dans l'application") print("2. Vérifiez que les colonnes sont bien détectées comme numériques") print("3. Les cercles ROUGES doivent apparaître sur les colonnes avec outliers univariés") print("4. Le cercle VIOLET doit apparaître (indicateur global multivarié)") print("5. Cliquez sur chaque indicateur pour voir les détails") print("6. Vérifiez la cohérence des outliers détectés") print() print("✨ Bon testing !") print("=" * 70) # Afficher un aperçu des outliers print() print("📋 APERÇU DES OUTLIERS DANS LE DATASET :") print("-" * 70) outliers_df = df[df["Type"].str.contains("Outlier", case=False, na=False)] print(outliers_df[["ID", "Type", "Age", "Experience", "Salaire", "Performance", "Heures_Sup"]].to_string(index=False)) if __name__ == "__main__": main()