Navigation : Index

Notebook de travail — Titanic: exploration, préparation et modèle simple

Ce notebook a pour objectif de charger le dataset Titanic (depuis une URL publique), d’effectuer une exploration et un traitement simples, puis d’entraîner un modèle de classification basique (régression logistique) et d’en présenter les métriques principales.

IMPORTANT — consignes de l’Admin avant exécution

  • Cellules Markdown : la première cellule (celle-ci) précise le contenu et ce que chaque section doit contenir. Les cellules Markdown suivantes doivent rester pédagogiques et explicites ; l’Admin a déjà ajouté des explications structurées pour chaque section.
  • Dépendances : NE PAS exécuter d’installation inline (%pip install) dans ce notebook. Indiquez ces paquets comme PREREQUIS à installer hors notebook (par ex. dans l’environnement du kernel) : pandas, numpy, scikit-learn, matplotlib, seaborn, joblib. Exemple (hors notebook) : pip install pandas numpy scikit-learn matplotlib seaborn joblib
  • Chemins de sortie : toutes les sorties persistantes (figures, modèles, tables) doivent être écrites dans des chemins relatifs sous le dossier outputs/, p. ex. outputs/models/, outputs/figures/. Aucun chemin absolu ni chemin temporaire du kernel ne doit apparaître dans les sorties.
  • Traitement des warnings prévisibles : le notebook doit éviter les avertissements connus à la source lorsque c’est possible (par ex. éviter les affectations chainées pandas et utiliser .copy()). Pour les warnings restant (FutureWarning, ConvergenceWarning de sklearn), utilisez un filtrage ciblé via la bibliothèque warnings au début du notebook afin de garder la sortie lisible.

Plan du notebook (sections et rôle des cellules)

    1. Prérequis (Markdown) : liste des dépendances à installer hors notebook et rappel sur outputs/.
    1. Préparation de l’environnement (code) : imports, configuration de warnings et création des dossiers outputs/ si nécessaire.
    1. Initialisation (code) : téléchargement (via pandas.read_csv) du jeu de données Titanic depuis une URL fiable, affichage sommaire et sauvegarde d’une copie dans outputs/data/titanic.csv.
    1. Traitement (code) : nettoyage minimal (gestion des valeurs manquantes, transformation des variables catégorielles), création d’un jeu X / y et séparation train/test. Éviter les SettingWithCopyWarning en utilisant .copy().
    1. Analyse (code + plots) : quelques visualisations simples (histogramme d’âge, taux de survie par sexe/classe) et sauvegarde des figures dans outputs/figures/.
    1. Modélisation et évaluation (code) : entraînement d’un pipeline simple (imputation, encodage minimal, StandardScaler, LogisticRegression), rapport des métriques (accuracy, precision, recall, f1) sur le jeu de test et sauvegarde du modèle sous outputs/models/.
    1. Conclusion (Markdown + code) : synthèse des résultats et chemins des fichiers sauvegardés.

Remarque administrative : le Coder devra remplir toutes les cellules de code laissées comme placeholders (“# Cellule N”). L’Admin exige des sorties explicites et des chemins relatifs. Après implémentation, le Reviewer pourra valider. Si Papermill ou le Reviewer signale une erreur, corriger la cellule indiquée puis relancer l’implémentation.

Fin de la cellule d’instruction de l’Admin.

# Cellule 0
# Vérification légère de l'environnement et rappel des prérequis (à installer hors notebook).
import sys
print(f"Python version: {sys.version.split()[0]}")
print("Prérequis (installer hors notebook) : pandas, numpy, scikit-learn, matplotlib, seaborn, joblib")
print("Les sorties persistantes seront écrites sous le dossier relatif 'outputs/'")
Python version: 3.13.14
Prérequis (installer hors notebook) : pandas, numpy, scikit-learn, matplotlib, seaborn, joblib
Les sorties persistantes seront écrites sous le dossier relatif 'outputs/'

1. Préparation de l’environnement

Cette cellule contient les imports, la configuration du filtrage des warnings et la création des dossiers outputs/ nécessaires pour sauvegarder les résultats.

  • Imports : pandas, numpy, sklearn, matplotlib, seaborn, joblib, os, warnings
  • Filtrage warnings : masquer FutureWarning et ConvergenceWarning (sklearn) et ignorer SettingWithCopyWarning en veillant toutefois à éviter les pratiques qui la provoquent.
  • Création des dossiers : outputs/, outputs/data/, outputs/figures/, outputs/models/.

La cellule de code suivante doit implémenter tout cela.

# Cellule 1
import os
import warnings

# Filtrage ciblé des warnings pour produire des sorties propres
from warnings import filterwarnings
filterwarnings('ignore', category=FutureWarning)
# sklearn ConvergenceWarning est parfois utile mais on le réduit ici
from sklearn.exceptions import ConvergenceWarning
filterwarnings('ignore', category=ConvergenceWarning)

import pandas as pd
# Ignorer SettingWithCopyWarning (nous évitons toutefois les pratiques qui le génèrent)
filterwarnings('ignore', category=pd.errors.SettingWithCopyWarning)

# On évite SettingWithCopyWarning en copiant les DataFrame quand nécessaire
import numpy as np
import matplotlib
import matplotlib.pyplot as plt
import seaborn as sns
import joblib

# Dossiers de sortie relatifs
OUTPUT_DIRS = ["outputs", "outputs/data", "outputs/figures", "outputs/models"]
for d in OUTPUT_DIRS:
    os.makedirs(d, exist_ok=True)

# Configuration visuelle
sns.set(style='whitegrid')
plt.rcParams['figure.dpi'] = 100

print("Imports effectués et dossiers outputs/ créés :", ", ".join(OUTPUT_DIRS))
Imports effectués et dossiers outputs/ créés : outputs, outputs/data, outputs/figures, outputs/models

2. Initialisation

Téléchargement et chargement du dataset Titanic via pandas.read_csv depuis une URL publique fiable (par ex. l’URL du dataset Titanic sur le dépôt de Kaggle n’est pas directement utilisable ; on utilisera un miroir public tel que l’URL fournie par ‘raw.githubusercontent.com’ si disponible).

Actions attendues dans la cellule de code : - Charger les données dans un DataFrame pandas df. - Afficher les 5 premières lignes et un résumé (.info()) succinct. - Sauvegarder une copie brute dans outputs/data/titanic.csv

Si le téléchargement échoue (connexions restreintes), documenter brièvement le problème via un message clair et lever une exception contrôlée.

# Cellule 2
import io

# URL publique pour le dataset Titanic (raw GitHub mirror)
TITANIC_URL = (
    "https://raw.githubusercontent.com/datasciencedojo/datasets/master/titanic.csv"
)

try:
    df = pd.read_csv(TITANIC_URL)
except Exception as e:
    raise RuntimeError(
        "Échec du téléchargement du dataset Titanic depuis internet. "
        "Vérifiez la connectivité ou fournissez le fichier localement."
    ) from e

# Affichage sommaire
print("Dimensions du DataFrame:", df.shape)
print("Colonnes:", df.columns.tolist())
print("Aperçu (5 premières lignes):")
print(df.head().to_string(index=False))

print("\nRésumé succinct (.info):")
buf = io.StringIO()
df.info(buf=buf)
info = buf.getvalue()
print(info)

# Sauvegarde d'une copie brute
raw_path = os.path.join("outputs", "data", "titanic.csv")
df.to_csv(raw_path, index=False)
print(f"Copie brute sauvegardée: {raw_path}")
Dimensions du DataFrame: (891, 12)
Colonnes: ['PassengerId', 'Survived', 'Pclass', 'Name', 'Sex', 'Age', 'SibSp', 'Parch', 'Ticket', 'Fare', 'Cabin', 'Embarked']
Aperçu (5 premières lignes):
 PassengerId  Survived  Pclass                                                Name    Sex  Age  SibSp  Parch           Ticket    Fare Cabin Embarked
           1         0       3                             Braund, Mr. Owen Harris   male 22.0      1      0        A/5 21171  7.2500   NaN        S
           2         1       1 Cumings, Mrs. John Bradley (Florence Briggs Thayer) female 38.0      1      0         PC 17599 71.2833   C85        C
           3         1       3                              Heikkinen, Miss. Laina female 26.0      0      0 STON/O2. 3101282  7.9250   NaN        S
           4         1       1        Futrelle, Mrs. Jacques Heath (Lily May Peel) female 35.0      1      0           113803 53.1000  C123        S
           5         0       3                            Allen, Mr. William Henry   male 35.0      0      0           373450  8.0500   NaN        S

Résumé succinct (.info):
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB

Copie brute sauvegardée: outputs\data\titanic.csv

3. Traitement

Ici, nous effectuons les manipulations et traitements nécessaires pour atteindre les résultats escomptés.

# Cellule 3
from sklearn.model_selection import train_test_split
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import OneHotEncoder, StandardScaler

# Travail sur une copie pour éviter SettingWithCopyWarning
df_clean = df.copy()

# Sélection de features simples
FEATURES = ["Pclass", "Sex", "Age", "SibSp", "Parch", "Fare", "Embarked"]
TARGET = "Survived"

# Traitement des valeurs manquantes
# Embarked a quelques valeurs manquantes -> remplir par la modalité la plus fréquente
if df_clean['Embarked'].isna().sum() > 0:
    most_freq = df_clean['Embarked'].mode(dropna=True)[0]
    df_clean['Embarked'] = df_clean['Embarked'].fillna(most_freq)

# Age et Fare -> laisser NaN pour imputer plus tard

# Garder seulement les colonnes d'intérêt
df_model = df_clean[[TARGET] + FEATURES].copy()

# Séparation train/test
X = df_model[FEATURES].copy()
y = df_model[TARGET].copy()

X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.25, random_state=42, stratify=y
)

print("Taille train:", X_train.shape, "Taille test:", X_test.shape)

# Sauvegarde des jeux bruts traités (optionnel)
X_train.to_csv(os.path.join('outputs','data','X_train.csv'), index=False)
y_train.to_csv(os.path.join('outputs','data','y_train.csv'), index=False)
X_test.to_csv(os.path.join('outputs','data','X_test.csv'), index=False)
y_test.to_csv(os.path.join('outputs','data','y_test.csv'), index=False)
print("Jeux train/test sauvegardés sous outputs/data/")
Taille train: (668, 7) Taille test: (223, 7)
Jeux train/test sauvegardés sous outputs/data/

4. Analyse

Nous effectuons ici les vérifications, agrégats et visualisations nécessaires pour valider les résultats obtenus.

# Cellule 4
import matplotlib.pyplot as plt
import seaborn as sns

# Analyse simple et sauvegarde des figures dans outputs/figures/
fig1_path = os.path.join('outputs','figures','age_histogram.png')
plt.figure(figsize=(6,4))
plt.hist(df['Age'].dropna(), bins=30, color='C0', edgecolor='k')
plt.xlabel('Age')
plt.ylabel('Count')
plt.title('Histogramme des âges (Titanic)')
plt.tight_layout()
plt.savefig(fig1_path)
plt.close()
print('Figure sauvegardée:', fig1_path)

# Taux de survie par sexe
fig2_path = os.path.join('outputs','figures','survival_by_sex.png')
surv_by_sex = df.groupby('Sex')['Survived'].mean().reset_index()
plt.figure(figsize=(5,4))
sns.barplot(data=surv_by_sex, x='Sex', y='Survived', palette='muted')
plt.ylabel('Taux de survie')
plt.title('Taux de survie par sexe')
plt.ylim(0,1)
plt.tight_layout()
plt.savefig(fig2_path)
plt.close()
print('Figure sauvegardée:', fig2_path)

# Taux de survie par classe
fig3_path = os.path.join('outputs','figures','survival_by_pclass.png')
surv_by_class = df.groupby('Pclass')['Survived'].mean().reset_index()
plt.figure(figsize=(6,4))
sns.barplot(data=surv_by_class, x='Pclass', y='Survived', palette='pastel')
plt.ylabel('Taux de survie')
plt.title('Taux de survie par Pclass')
plt.ylim(0,1)
plt.tight_layout()
plt.savefig(fig3_path)
plt.close()
print('Figure sauvegardée:', fig3_path)

print('Toutes les figures sont dans le dossier outputs/figures/')
Figure sauvegardée: outputs\figures\age_histogram.png
Figure sauvegardée: outputs\figures\survival_by_sex.png
Figure sauvegardée: outputs\figures\survival_by_pclass.png
Toutes les figures sont dans le dossier outputs/figures/

5. Conclusion

Concluons ici l’exécution et la validation de la tâche. Récapitulons les résultats obtenus. La cellule suivante peut servir de synthèse.

# Cellule 5
from sklearn.pipeline import Pipeline
from sklearn.compose import ColumnTransformer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, classification_report

# Préparer transformateurs
numeric_features = ["Age", "SibSp", "Parch", "Fare"]
numeric_transformer = Pipeline(steps=[
    ("imputer", SimpleImputer(strategy='median')),
    ("scaler", StandardScaler())
])

categorical_features = ["Pclass", "Sex", "Embarked"]
# Pour Pclass on peut laisser tel quel (numérique ordinal) mais on encode tout en one-hot pour simplicité
categorical_transformer = Pipeline(steps=[
    ("imputer", SimpleImputer(strategy='most_frequent')),
    ("onehot", OneHotEncoder(handle_unknown='ignore'))
])

preprocessor = ColumnTransformer(
    transformers=[
        ("num", numeric_transformer, numeric_features),
        ("cat", categorical_transformer, categorical_features)
    ]
)

clf = Pipeline(steps=[
    ("preprocessor", preprocessor),
    ("clf", LogisticRegression(max_iter=1000, random_state=42))
])

# Entraînement
clf.fit(X_train, y_train)

# Évaluation
y_pred = clf.predict(X_test)
acc = accuracy_score(y_test, y_pred)
prec = precision_score(y_test, y_pred)
rec = recall_score(y_test, y_pred)
f1 = f1_score(y_test, y_pred)

print("Métriques sur le jeu de test:")
print(f"Accuracy: {acc:.4f}")
print(f"Precision: {prec:.4f}")
print(f"Recall: {rec:.4f}")
print(f"F1-score: {f1:.4f}")

# Rapport détaillé
print('\nRapport de classification:\n')
print(classification_report(y_test, y_pred, digits=4))

# Sauvegarde du modèle
model_path = os.path.join('outputs','models','titanic_logreg.joblib')
joblib.dump(clf, model_path)
print('Modèle sauvegardé:', model_path)

# Sauvegarde des métriques dans un petit fichier texte
metrics_path = os.path.join('outputs','models','metrics.txt')
with open(metrics_path, 'w') as f:
    f.write(f"accuracy={acc:.6f}\nprecision={prec:.6f}\nrecall={rec:.6f}\nf1={f1:.6f}\n")
print('Métriques sauvegardées:', metrics_path)

print('\nTerminé. Fichiers produits:')
print('-', os.path.join('outputs','data','titanic.csv'))
print('-', os.path.join('outputs','figures','age_histogram.png'))
print('-', os.path.join('outputs','models','titanic_logreg.joblib'))
Métriques sur le jeu de test:
Accuracy: 0.7758
Precision: 0.7250
Recall: 0.6744
F1-score: 0.6988

Rapport de classification:

              precision    recall  f1-score   support

           0     0.8042    0.8394    0.8214       137
           1     0.7250    0.6744    0.6988        86

    accuracy                         0.7758       223
   macro avg     0.7646    0.7569    0.7601       223
weighted avg     0.7737    0.7758    0.7741       223

Modèle sauvegardé: outputs\models\titanic_logreg.joblib
Métriques sauvegardées: outputs\models\metrics.txt

Terminé. Fichiers produits:
- outputs\data\titanic.csv
- outputs\figures\age_histogram.png
- outputs\models\titanic_logreg.joblib

Lecture ancrée. Le modèle de régression logistique entraîné sur le dataset Titanic atteint des performances honorables avec une précision (accuracy) de 77.58% sur le jeu de test. Les autres métriques sont également instructives : une précision (precision) de 72.50% indique que lorsque le modèle prédit la survie, il a raison dans 72.5% des cas, tandis qu’un recall de 67.44% signifie qu’il identifie correctement 67.44% de tous les passagers ayant effectivement survécu. Le F1-score de 69.88%, qui harmonise précision et recall, confirme que le modèle capture correctement les patterns de survie dans ce dataset historique.

Retour au sommet