# Installation des bibliothèques (si nécessaire)
# !pip install scikit-learn pandas numpy matplotlib seaborn
# Imports
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler, LabelEncoder
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score, classification_report, confusion_matrix
from sklearn.pipeline import Pipeline
# Configuration
plt.style.use('default')
sns.set_palette("husl")
np.random.seed(42)
print("✓ Bibliothèques importées avec succès")Séance 3: TP1 - Pipeline de Classification Binaire
Objectifs du TP
À la fin de ce TP, vous serez capable de:
- Charger et explorer un dataset
- Préparer les données pour l’apprentissage
- Créer un pipeline de prétraitement avec Scikit-learn
- Entraîner un modèle de classification binaire
- Évaluer les performances du modèle
📎 Lien du TP : TP1 — Pipeline Classification
1. Configuration de l’Environnement
2. Chargement et Exploration des Données
2.1 Chargement du Dataset Titanic
# Chargement depuis seaborn
titanic = sns.load_dataset('titanic')
# Affichage des premières lignes
print("Aperçu des données:")
print(titanic.head())
print(f"\nDimensions: {titanic.shape}")
print(f"Colonnes: {titanic.columns.tolist()}")2.2 Exploration Initiale
# Informations générales
print("Informations sur le dataset:")
print(titanic.info())
print("\nStatistiques descriptives:")
print(titanic.describe())
# Vérification des valeurs manquantes
print("\nValeurs manquantes:")
print(titanic.isnull().sum())
# Distribution de la variable cible
print("\nDistribution de la survie:")
print(titanic['survived'].value_counts())
print(f"\nTaux de survie: {titanic['survived'].mean():.2%}")2.3 Visualisations Exploratoires
# Figure 1: Distribution de la survie
fig, axes = plt.subplots(2, 2, figsize=(14, 10))
# Survie globale
axes[0, 0].pie(
titanic['survived'].value_counts(),
labels=['Décédé', 'Survivant'],
autopct='%1.1f%%',
startangle=90,
colors=['#ff6b6b', '#51cf66']
)
axes[0, 0].set_title('Distribution de la Survie')
# Survie par sexe
survival_by_sex = titanic.groupby(['sex', 'survived']).size().unstack()
survival_by_sex.plot(kind='bar', ax=axes[0, 1], color=['#ff6b6b', '#51cf66'])
axes[0, 1].set_title('Survie par Sexe')
axes[0, 1].set_xlabel('Sexe')
axes[0, 1].set_ylabel('Nombre de passagers')
axes[0, 1].legend(['Décédé', 'Survivant'])
axes[0, 1].tick_params(axis='x', rotation=0)
# Survie par classe
survival_by_class = titanic.groupby(['pclass', 'survived']).size().unstack()
survival_by_class.plot(kind='bar', ax=axes[1, 0], color=['#ff6b6b', '#51cf66'])
axes[1, 0].set_title('Survie par Classe')
axes[1, 0].set_xlabel('Classe')
axes[1, 0].set_ylabel('Nombre de passagers')
axes[1, 0].legend(['Décédé', 'Survivant'])
# Distribution de l'âge
axes[1, 1].hist(titanic[titanic['survived']==0]['age'].dropna(),
alpha=0.5, label='Décédé', bins=30, color='#ff6b6b')
axes[1, 1].hist(titanic[titanic['survived']==1]['age'].dropna(),
alpha=0.5, label='Survivant', bins=30, color='#51cf66')
axes[1, 1].set_title('Distribution de l\'âge par survie')
axes[1, 1].set_xlabel('Âge')
axes[1, 1].set_ylabel('Fréquence')
axes[1, 1].legend()
plt.tight_layout()
plt.show()3. Préparation des Données
3.1 Sélection des Features
# Sélection des colonnes pertinentes
features = ['pclass', 'sex', 'age', 'sibsp', 'parch', 'fare', 'embarked']
target = 'survived'
# Création du dataset de travail
df = titanic[features + [target]].copy()
print(f"Dataset de travail: {df.shape}")
print(f"\nValeurs manquantes:")
print(df.isnull().sum())3.2 Traitement des Valeurs Manquantes
# Stratégies de traitement
# 1. Age: remplir avec la médiane
df['age'].fillna(df['age'].median(), inplace=True)
# 2. Embarked: remplir avec le mode (valeur la plus fréquente)
df['embarked'].fillna(df['embarked'].mode()[0], inplace=True)
# 3. Fare: remplir avec la médiane (si manquant)
df['fare'].fillna(df['fare'].median(), inplace=True)
# Vérification
print("Après traitement:")
print(df.isnull().sum())3.3 Encodage des Variables Catégorielles
# Encodage de 'sex'
df['sex'] = df['sex'].map({'male': 0, 'female': 1})
# Encodage de 'embarked' (One-Hot Encoding)
df = pd.get_dummies(df, columns=['embarked'], prefix='embarked', drop_first=True)
print("Dataset après encodage:")
print(df.head())
print(f"\nNouvelles dimensions: {df.shape}")3.4 Séparation Features / Target
# Séparation X (features) et y (target)
X = df.drop('survived', axis=1)
y = df['survived']
print(f"X shape: {X.shape}")
print(f"y shape: {y.shape}")
print(f"\nFeatures utilisées:\n{X.columns.tolist()}")4. Split Train/Validation/Test
4.1 Split Train/Test
# Split 80/20
X_train, X_test, y_train, y_test = train_test_split(
X, y,
test_size=0.2, # 20% pour le test
random_state=42, # reproductibilité
stratify=y # préserver la distribution des classes
)
print(f"Train set: {X_train.shape}")
print(f"Test set: {X_test.shape}")
# Vérification de la distribution
print(f"\nDistribution train: {y_train.value_counts(normalize=True)}")
print(f"Distribution test: {y_test.value_counts(normalize=True)}")4.2 Split Train/Validation (optionnel)
# Optionnel: créer un ensemble de validation
X_train_full, X_val, y_train_full, y_val = train_test_split(
X_train, y_train,
test_size=0.2, # 20% du train pour validation
random_state=42,
stratify=y_train
)
print(f"Train full: {X_train_full.shape}")
print(f"Validation: {X_val.shape}")
print(f"Test: {X_test.shape}")5. Pipeline de Prétraitement et Entraînement
5.1 Création du Pipeline
# Pipeline: Standardisation + Modèle
pipeline = Pipeline([
('scaler', StandardScaler()), # Étape 1: Standardisation
('classifier', LogisticRegression(max_iter=1000, random_state=42)) # Étape 2: Modèle
])
print("Pipeline créé:")
print(pipeline)5.2 Entraînement du Modèle
# Entraînement
print("Entraînement en cours...")
pipeline.fit(X_train, y_train)
print("✓ Entraînement terminé")
# Prédictions
y_train_pred = pipeline.predict(X_train)
y_test_pred = pipeline.predict(X_test)
print("✓ Prédictions effectuées")6. Évaluation Initiale
6.1 Accuracy
# Calcul de l'accuracy
train_accuracy = accuracy_score(y_train, y_train_pred)
test_accuracy = accuracy_score(y_test, y_test_pred)
print(f"Accuracy Train: {train_accuracy:.4f} ({train_accuracy*100:.2f}%)")
print(f"Accuracy Test: {test_accuracy:.4f} ({test_accuracy*100:.2f}%)")
# Analyse de l'overfitting
diff = train_accuracy - test_accuracy
print(f"\nDifférence Train-Test: {diff:.4f}")
if diff < 0.05:
print("→ Bon équilibre biais-variance")
elif diff < 0.10:
print("→ Léger overfitting")
else:
print("→ Overfitting significatif")6.2 Matrice de Confusion
# Calcul de la matrice de confusion
cm = confusion_matrix(y_test, y_test_pred)
# Visualisation
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=['Décédé', 'Survivant'],
yticklabels=['Décédé', 'Survivant'])
plt.title('Matrice de Confusion - Test Set')
plt.ylabel('Vraie Classe')
plt.xlabel('Classe Prédite')
plt.tight_layout()
plt.show()
# Interprétation
tn, fp, fn, tp = cm.ravel()
print(f"\nVrais Négatifs (TN): {tn}")
print(f"Faux Positifs (FP): {fp}")
print(f"Faux Négatifs (FN): {fn}")
print(f"Vrais Positifs (TP): {tp}")6.3 Rapport de Classification
# Rapport détaillé
print("\nRapport de Classification:")
print(classification_report(y_test, y_test_pred,
target_names=['Décédé', 'Survivant']))7. Comparaison de Plusieurs Modèles
# Définition des modèles
models = {
'Logistic Regression': LogisticRegression(max_iter=1000, random_state=42),
'Decision Tree': DecisionTreeClassifier(max_depth=5, random_state=42),
'Random Forest': RandomForestClassifier(n_estimators=100, max_depth=5, random_state=42)
}
# Entraînement et évaluation
results = {}
for name, model in models.items():
# Pipeline pour chaque modèle
pipe = Pipeline([
('scaler', StandardScaler()),
('classifier', model)
])
# Entraînement
pipe.fit(X_train, y_train)
# Évaluation
train_score = pipe.score(X_train, y_train)
test_score = pipe.score(X_test, y_test)
results[name] = {
'train': train_score,
'test': test_score,
'diff': train_score - test_score
}
print(f"\n{name}:")
print(f" Train Accuracy: {train_score:.4f}")
print(f" Test Accuracy: {test_score:.4f}")
print(f" Différence: {train_score - test_score:.4f}")
# Visualisation comparative
df_results = pd.DataFrame(results).T
df_results[['train', 'test']].plot(kind='bar', figsize=(10, 6))
plt.title('Comparaison des Performances des Modèles')
plt.xlabel('Modèle')
plt.ylabel('Accuracy')
plt.legend(['Train', 'Test'])
plt.xticks(rotation=45, ha='right')
plt.ylim([0, 1])
plt.grid(axis='y', alpha=0.3)
plt.tight_layout()
plt.show()8. Analyse des Prédictions
8.1 Exemples de Prédictions
# Prédictions avec probabilités
y_proba = pipeline.predict_proba(X_test)
# Affichage de quelques exemples
n_samples = 5
indices = np.random.choice(len(X_test), n_samples, replace=False)
print("Exemples de prédictions:\n")
for idx in indices:
actual = y_test.iloc[idx]
predicted = y_test_pred[idx]
proba = y_proba[idx]
print(f"Passager {idx}:")
print(f" Vraie classe: {'Survivant' if actual == 1 else 'Décédé'}")
print(f" Prédiction: {'Survivant' if predicted == 1 else 'Décédé'}")
print(f" Probabilités: Décédé={proba[0]:.2%}, Survivant={proba[1]:.2%}")
print(f" Correct: {'+' if actual == predicted else '+'}")
print()8.2 Analyse des Erreurs
# Identification des erreurs
errors = X_test[y_test != y_test_pred].copy()
errors['actual'] = y_test[y_test != y_test_pred]
errors['predicted'] = y_test_pred[y_test != y_test_pred]
print(f"Nombre d'erreurs: {len(errors)}")
print(f"Taux d'erreur: {len(errors)/len(X_test):.2%}")
print("\nQuelques erreurs:")
print(errors.head())
# Analyse des caractéristiques des erreurs
print("\nCaractéristiques moyennes des erreurs vs correctes:")
correct = X_test[y_test == y_test_pred]
comparison = pd.DataFrame({
'Erreurs': errors.drop(['actual', 'predicted'], axis=1).mean(),
'Correctes': correct.mean()
})
print(comparison)Exercices Pratiques
Résumé du TP
Checklist de Validation
Pour Aller Plus Loin
- Testez d’autres features (titre extrait du nom, cabine, etc.)
- Expérimentez avec le seuil de décision (au lieu de 0.5)
- Utilisez la validation croisée (voir TP2)
- Essayez d’autres algorithmes (SVM, Gradient Boosting)