🚀 TP Synthèse : Data Wrangling & Sauvetage Spatial

%pip install pandas numpy
Requirement already satisfied: pandas in /home/aptitek/Documents/Aptispace/.venv/lib/python3.14/site-packages (3.0.3)
Requirement already satisfied: numpy in /home/aptitek/Documents/Aptispace/.venv/lib/python3.14/site-packages (2.4.5)
Requirement already satisfied: python-dateutil>=2.8.2 in /home/aptitek/Documents/Aptispace/.venv/lib/python3.14/site-packages (from pandas) (2.9.0.post0)
Requirement already satisfied: six>=1.5 in /home/aptitek/Documents/Aptispace/.venv/lib/python3.14/site-packages (from python-dateutil>=2.8.2->pandas) (1.17.0)
Note: you may need to restart the kernel to use updated packages.

Mission : Le vaisseau spatial de croisière Spaceship Titanic a percuté une anomalie spatio-temporelle. Près de la moitié des passagers ont été téléportés dans une dimension alternative ! La base de données du vaisseau a été gravement corrompue lors du choc.

En tant que Data Engineer d’urgence, vous devez nettoyer et préparer les données (Wrangling) pour que notre IA de sauvetage puisse ensuite prédire qui a disparu et qui est encore à bord.

Dataset source : Kaggle - Spaceship Titanic

# Importation de notre boîte à outils
import pandas as pd
import numpy as np

df = pd.read_csv('train.csv')
taille_initiale = df.shape  # Sauvegarde de la taille de départ sans copier le DataFrame

print("Aperçu des données corrompues :")
display(df.head(10))
Aperçu des données corrompues :
PassengerId HomePlanet CryoSleep Cabin Destination Age VIP RoomService FoodCourt ShoppingMall Spa VRDeck Name Transported
0 0001_01 Europa False B/0/P TRAPPIST-1e 39.0 False 0.0 0.0 0.0 0.0 0.0 Maham Ofracculy False
1 0002_01 Earth False F/0/S TRAPPIST-1e 24.0 False 109.0 9.0 25.0 549.0 44.0 Juanna Vines True
2 0003_01 Europa False A/0/S TRAPPIST-1e 58.0 True 43.0 3576.0 0.0 6715.0 49.0 Altark Susent False
3 0003_02 Europa False A/0/S TRAPPIST-1e 33.0 False 0.0 1283.0 371.0 3329.0 193.0 Solam Susent False
4 0004_01 Earth False F/1/S TRAPPIST-1e 16.0 False 303.0 70.0 151.0 565.0 2.0 Willy Santantines True
5 0005_01 Earth False F/0/P PSO J318.5-22 44.0 False 0.0 483.0 0.0 291.0 0.0 Sandie Hinetthews True
6 0006_01 Earth False F/2/S TRAPPIST-1e 26.0 False 42.0 1539.0 3.0 0.0 0.0 Billex Jacostaffey True
7 0006_02 Earth True G/0/S TRAPPIST-1e 28.0 False 0.0 0.0 0.0 0.0 NaN Candra Jacostaffey True
8 0007_01 Earth False F/3/S TRAPPIST-1e 35.0 False 0.0 785.0 17.0 216.0 0.0 Andona Beston True
9 0008_01 Europa True B/1/P 55 Cancri e 14.0 False 0.0 0.0 0.0 0.0 0.0 Erraiam Flatic True

🛠️ Étape 1 : Gestion des valeurs manquantes (_21_valeurs_manquantes)

L’anomalie a effacé certaines informations cruciales. Une IA ne peut pas s’entraîner sur du vide (NaN). Nous devons boucher ces trous de manière intelligente.

  1. Analyse : Regardons l’étendue des dégâts.
  2. Imputation : Remplaçons l’âge manquant par l’âge médian du vaisseau, et le statut VIP par la valeur la plus fréquente (le mode).
# 1. Bilan des valeurs manquantes
print("--- Trous dans la base de données ---")
display(df.isnull().sum()[df.isnull().sum() > 0])
--- Trous dans la base de données ---
HomePlanet      201
CryoSleep       217
Cabin           199
Destination     182
Age             179
VIP             203
RoomService     181
FoodCourt       183
ShoppingMall    208
Spa             183
VRDeck          188
Name            200
dtype: int64


# 2. Remplissage (Imputation)
# On remplace les âges manquants par la médiane (moins sensible aux valeurs extrêmes que la moyenne)
df['Age'] = df['Age'].fillna(df['Age'].median())

# On remplace le statut VIP manquant par 'False' (statistiquement le plus probable)
df['VIP'] = df['VIP'].fillna(False)

# 3. Suppression
# Pour la cabine, l'information est trop complexe pour l'inventer. On supprime les lignes sans cabine.
df = df.dropna(subset=['Cabin'])

print(f"\nNettoyage effectué. Il reste {len(df)} passagers viables pour l'analyse.")

Nettoyage effectué. Il reste 8494 passagers viables pour l'analyse.

🪚 Étape 2 : Harmonisation et Parsing (_22_harmonisation)

La colonne Cabin est un cauchemar : elle contient le pont, le numéro et le côté du vaisseau, tout collé ensemble (ex: B/0/P). L’IA ne comprendra rien à cette chaîne de caractères. Nous devons la parser (la découper) en trois colonnes distinctes et harmonisées.

# A VOUS DE JOUER :
# Utilisez la méthode .str.split() de Pandas pour découper la colonne 'Cabin'

# 1. On sépare la colonne 'Cabin' et on assigne les nouvelles colonnes d'un coup
df[['Deck', 'NumCabin', 'Side']] = df['Cabin'].str.split('/', expand=True)

# 2. On supprime la colonne d'origine en place (sans faire de copie du DataFrame)
df.drop(columns=['Cabin'], inplace=True)

display(df[['Name', 'Deck', 'NumCabin', 'Side']].head(3))
Name Deck NumCabin Side
0 Maham Ofracculy B 0 P
1 Juanna Vines F 0 S
2 Altark Susent A 0 S

🧪 Étape 3 : Transformation et Feature Engineering (_23_transformation)

Le Feature Engineering consiste à créer de nouvelles variables plus pertinentes à partir de celles existantes. Nous avons les dépenses des passagers éparpillées dans 5 boutiques différentes (RoomService, FoodCourt, ShoppingMall, Spa, VRDeck).

Pour aider notre modèle, créons une nouvelle variable Total_Spent qui regroupe toutes ces dépenses !

# On liste les colonnes financières
colonnes_depenses = ['RoomService', 'FoodCourt', 'ShoppingMall', 'Spa', 'VRDeck']

# On comble les valeurs manquantes financières par 0 (s'ils n'ont rien dépensé, c'est 0)
df[colonnes_depenses] = df[colonnes_depenses].fillna(0)

# A VOUS DE JOUER :
# Créez la colonne 'Total_Spent' en additionnant les colonnes et en les supprimant au fur et à mesure
df['Total_Spent'] = 0
for col in colonnes_depenses:
    df['Total_Spent'] += df[col]
    df.drop(columns=[col], inplace=True)

# Vérification pour le passager VIP
print("Les plus gros dépensiers du vaisseau :")
display(df[['Name', 'VIP', 'Total_Spent']].sort_values(by='Total_Spent', ascending=False).head(3))
Les plus gros dépensiers du vaisseau :
Name VIP Total_Spent
5722 Markar Radisiouss False 35987.0
2067 Pulchib Quidedbolt True 31076.0
1213 Scharab Conale True 31074.0

🧮 Étape 4 : Encodage des catégories (_24_encodage)

L’algorithme de sauvetage ne comprend que les mathématiques. Or, nous avons des planètes d’origine (HomePlanet) sous forme de texte (“Earth”, “Europa”, “Mars”). Nous allons utiliser la technique du One-Hot Encoding (création de variables muettes) pour transformer ce texte en colonnes binaires composées de 0 et de 1.

print(f"Format avant encodage : {df.shape}")

# 1. On supprime en place les variables textuelles inexploitables par l'IA (le nom et l'ID)
df.drop(columns=['PassengerId', 'Name'], inplace=True)

# 2. Conversion en place des booléens (True/False) en entiers (1/0)
colonnes_bool = ['CryoSleep', 'VIP', 'Transported']
for col in colonnes_bool:
    df[col] = df[col].astype(bool)

# 3. One-Hot Encoding sur les planètes et les ponts (le résultat final remplace directement df)
df = pd.get_dummies(df, columns=['HomePlanet', 'Destination', 'Deck', 'Side'])

print(f"Format après encodage : {df.shape}")
print("\n✅ Base de données prête pour l'algorithme d'Intelligence Artificielle !")
display(df.head(10))
Format avant encodage : (8494, 12)
Format après encodage : (8494, 22)

✅ Base de données prête pour l'algorithme d'Intelligence Artificielle !
CryoSleep Age VIP Transported NumCabin Total_Spent HomePlanet_Earth HomePlanet_Europa HomePlanet_Mars Destination_55 Cancri e ... Deck_A Deck_B Deck_C Deck_D Deck_E Deck_F Deck_G Deck_T Side_P Side_S
0 False 39.0 False False 0 0.0 False True False False ... False True False False False False False False True False
1 False 24.0 False True 0 736.0 True False False False ... False False False False False True False False False True
2 False 58.0 True False 0 10383.0 False True False False ... True False False False False False False False False True
3 False 33.0 False False 0 5176.0 False True False False ... True False False False False False False False False True
4 False 16.0 False True 1 1091.0 True False False False ... False False False False False True False False False True
5 False 44.0 False True 0 774.0 True False False False ... False False False False False True False False True False
6 False 26.0 False True 2 1584.0 True False False False ... False False False False False True False False False True
7 True 28.0 False True 0 0.0 True False False False ... False False False False False False True False False True
8 False 35.0 False True 3 1018.0 True False False False ... False False False False False True False False False True
9 True 14.0 False True 1 0.0 False True False True ... False True False False False False False False True False

10 rows Ă— 22 columns

# Comparaison de la taille avant / après sans copie de DataFrame
print("--- 📊 BILAN DU DATA WRANGLING ---")
print(f"Format initial (Données brutes) : {taille_initiale[0]} lignes, {taille_initiale[1]} colonnes")
print(f"Format final (Données prêtes)  : {df.shape[0]} lignes, {df.shape[1]} colonnes")
print(f"Passagers éliminés (NaNs)      : {taille_initiale[0] - df.shape[0]} ({((taille_initiale[0] - df.shape[0])/taille_initiale[0]*100):.1f}%)")
print(f"Variation des colonnes         : {df.shape[1] - taille_initiale[1]:+d}")
--- 📊 BILAN DU DATA WRANGLING ---
Format initial (Données brutes) : 8693 lignes, 14 colonnes
Format final (Données prêtes)  : 8494 lignes, 22 colonnes
Passagers éliminés (NaNs)      : 199 (2.3%)
Variation des colonnes         : +8
display(df.columns)
Index(['CryoSleep', 'Age', 'VIP', 'Transported', 'NumCabin', 'Total_Spent',
       'HomePlanet_Earth', 'HomePlanet_Europa', 'HomePlanet_Mars',
       'Destination_55 Cancri e', 'Destination_PSO J318.5-22',
       'Destination_TRAPPIST-1e', 'Deck_A', 'Deck_B', 'Deck_C', 'Deck_D',
       'Deck_E', 'Deck_F', 'Deck_G', 'Deck_T', 'Side_P', 'Side_S'],
      dtype='str')