TP12 — Pandas pour le Machine Learning¶

Cours : Machine Learning
Enseignant : Pr El Alami
Séance : TP12 — Pandas

Nom de l’étudiant : à compléter

Objectif : apprendre à manipuler des données avec Pandas pour préparer un dataset utilisable en Machine Learning.

0. Import des bibliothèques¶

In [2]:
import pandas as pd      # bibliothèque principale pour les tableaux de données
import numpy as np       # utilisé pour le calcul numérique
import matplotlib.pyplot as plt  # pour les graphiques

# Option : afficher les DataFrames avec plus de lisibilité
pd.set_option("display.max_rows", 10)
pd.set_option("display.max_columns", 10)

1. Series : la base (colonne 1D)¶

Une Series est comme une colonne de données, avec un index (les étiquettes de lignes).

1.1 Créer une Series à partir d’une liste¶

In [3]:
# Une Series est comme une liste, mais avec un index (étiquettes de lignes)
s = pd.Series([2, 4, 6, 8, 10])

print("Series s :")
print(s)
Series s :
0     2
1     4
2     6
3     8
4    10
dtype: int64

1.2 Créer une Series à partir d’un dictionnaire¶

In [4]:
# Les clés du dictionnaire deviennent les index (noms des lignes)
hauteur = {"Snaa": 187, "Ali": 178, "Aicha": 170, "Fatima": 165}

s_altura = pd.Series(hauteur)

print("Series des hauteurs :")
print(s_altura)
Series des hauteurs :
Snaa      187
Ali       178
Aicha     170
Fatima    165
dtype: int64

1.3 Accéder aux éléments d’une Series¶

In [21]:
# Accès par position (comme une liste) : 2e élément
print("Par position s_Hauteur.iloc[1] :", s_altura.iloc[1])

# Accès par nom (index) : ligne 'Pedro'
print("Par nom s_Hauteur['Ali'] :", s_altura["Ali"])
Par position s_Hauteur.iloc[1] : 178
Par nom s_Hauteur['Ali'] : 178

2. DataFrame : tableau 2D pour les datasets¶

Un DataFrame est un tableau 2D (lignes × colonnes), très utilisé pour représenter un dataset en Machine Learning.

2.1 Créer un DataFrame à partir d’un dictionnaire de Series¶

In [14]:
personas = {
    "poids": pd.Series([84, 90, 56, 64], index=["Sanaa","Ali","Aicha","Fatima"]),
    "Hauteur": pd.Series({"Sanaa":187, "Ali":178, "Aicha":170, "Fatima":165}),
    "Enfants": pd.Series([2, 3], index=["Ali", "Fatima"])  # NaN pour les autres
}

df = pd.DataFrame(personas)

print("DataFrame df :")
print(df)
DataFrame df :
        poids  Hauteur  Enfants
Aicha      56      170      NaN
Ali        90      178      2.0
Fatima     64      165      3.0
Sanaa      84      187      NaN

2.2 Accéder aux colonnes¶

In [16]:
# Une seule colonne → Series
print("Hauteur, poids :")
print(df["poids"])

# Plusieurs colonnes → DataFrame
print("Colonnes poids + Hauteur :")
print(df[["poids", "Hauteur"]])
Hauteur, poids :
Aicha     56
Ali       90
Fatima    64
Sanaa     84
Name: poids, dtype: int64
Colonnes poids + Hauteur :
        poids  Hauteur
Aicha      56      170
Ali        90      178
Fatima     64      165
Sanaa      84      187

2.3 Accéder aux lignes (loc / iloc)¶

In [17]:
# loc : par nom d’index (étiquette de ligne)
print("Ligne 'Ali' avec loc :")
print(df.loc["Ali"])

# iloc : par position (0 = 1ère ligne, etc.)
print("3ème ligne (position 2) avec iloc :")
print(df.iloc[2])

# Sous-ensemble de lignes (slicing)
print("Lignes 1 à 2 :")
print(df.iloc[1:3])
Ligne 'Ali' avec loc :
poids       90.0
Hauteur    178.0
Enfants      2.0
Name: Ali, dtype: float64
3ème ligne (position 2) avec iloc :
poids       64.0
Hauteur    165.0
Enfants      3.0
Name: Fatima, dtype: float64
Lignes 1 à 2 :
        poids  Hauteur  Enfants
Ali        90      178      2.0
Fatima     64      165      3.0

3. Filtrer les données (très utilisé en ML)¶

Les filtres permettent de sélectionner uniquement les lignes qui respectent une condition (par exemple, poids > 80).

3.1 Filtre logique simple¶

In [26]:
# Condition : poids > 80
mas_de_80 = df["poids"] > 80
print("Condition (poids > 80) :")
print(mas_de_80)

# Appliquer le filtre au DataFrame
print("Personnes avec poids > 80 :")
print(df[df["poids"] > 80])
Condition (poids > 80) :
Aicha     False
Ali        True
Fatima    False
Sanaa      True
Name: poids, dtype: bool
Personnes avec poids > 80 :
       poids  Hauteur  Enfants
Ali       90      178      2.0
Sanaa     84      187      NaN

3.2 Filtre avec query()¶

In [27]:
# Syntaxe proche du langage SQL
filtre = df.query("Hauteur >= 170 and poids > 60")

print("Personnes avec Hauteru >= 170 ET poids > 60 :")
print(filtre)
Personnes avec Hauteru >= 170 ET poids > 60 :
       poids  Hauteur  Enfants
Ali       90      178      2.0
Sanaa     84      187      NaN

4. Modifier un DataFrame¶

Ajouter, modifier ou supprimer des colonnes est très fréquent lorsqu’on prépare un dataset pour le Machine Learning.

4.1 Ajouter des colonnes¶

In [33]:
# Ajouter l’année de naissance
df["année_naissance"] = [1990, 1987, 1980, 1994]

# Créer une colonne calculée : âge en 2020
df["Age"] = 2020 - df["année_naissance"]

print("DataFrame après ajout des colonnes :")
print(df)
DataFrame après ajout des colonnes :
        poids  Hauteur  Enfants  Age  année_naissance
Aicha      56      170      NaN   30             1990
Ali        90      178      2.0   33             1987
Fatima     64      165      3.0   40             1980
Sanaa      84      187      NaN   26             1994

4.2 Utiliser assign() pour créer un nouveau DataFrame¶

In [34]:
# Crée un NOUVEAU DataFrame avec une colonne mascotas
df_mod = df.assign(mascotas=[1, 3, 0, 0])

print("df_mod (avec mascotas) :")
print(df_mod)

print("df original (inchangé) :")
print(df)
df_mod (avec mascotas) :
        poids  Hauteur  Enfants  Age  année_naissance  mascotas
Aicha      56      170      NaN   30             1990         1
Ali        90      178      2.0   33             1987         3
Fatima     64      165      3.0   40             1980         0
Sanaa      84      187      NaN   26             1994         0
df original (inchangé) :
        poids  Hauteur  Enfants  Age  année_naissance
Aicha      56      170      NaN   30             1990
Ali        90      178      2.0   33             1987
Fatima     64      165      3.0   40             1980
Sanaa      84      187      NaN   26             1994

4.3 Supprimer une colonne¶

In [35]:
# Supprimer dans df (modifie df)
del df["année_naissance"]

# Créer une copie sans la colonne "hijos" (df reste intact)
df_sans_Enfants = df.drop(["Enfants"], axis=1)

print("df après suppression de année_naissance :")
print(df)

print("df_sans_enfants (copie sans Enfants) :")
print(df_sans_Enfants)
df après suppression de année_naissance :
        poids  Hauteur  Enfants  Age
Aicha      56      170      NaN   30
Ali        90      178      2.0   33
Fatima     64      165      3.0   40
Sanaa      84      187      NaN   26
df_sans_enfants (copie sans Enfants) :
        poids  Hauteur  Age
Aicha      56      170   30
Ali        90      178   33
Fatima     64      165   40
Sanaa      84      187   26

5. Gestion des valeurs manquantes (NaN)¶

Les modèles de Machine Learning ne supportent pas les valeurs manquantes : il faut les détecter et les traiter.

In [36]:
print("DataFrame avec NaN (s'il y en a) :")
print(df)

# Voir où sont les NaN
print("Valeurs manquantes (True = NaN) :")
print(df.isna())

# Compter les NaN par colonne
print("Nombre de NaN par colonne :")
print(df.isna().sum())
DataFrame avec NaN (s'il y en a) :
        poids  Hauteur  Enfants  Age
Aicha      56      170      NaN   30
Ali        90      178      2.0   33
Fatima     64      165      3.0   40
Sanaa      84      187      NaN   26
Valeurs manquantes (True = NaN) :
        poids  Hauteur  Enfants    Age
Aicha   False    False     True  False
Ali     False    False    False  False
Fatima  False    False    False  False
Sanaa   False    False     True  False
Nombre de NaN par colonne :
poids      0
Hauteur    0
Enfants    2
Age        0
dtype: int64

5.1 Supprimer les lignes avec NaN¶

In [37]:
df_sans_nan = df.dropna()  # enlève les lignes contenant au moins un NaN

print("df_sans_nan (lignes complètes uniquement) :")
print(df_sans_nan)
df_sans_nan (lignes complètes uniquement) :
        poids  Hauteur  Enfants  Age
Ali        90      178      2.0   33
Fatima     64      165      3.0   40

5.2 Remplacer les NaN par une valeur¶

In [39]:
# Remplacer NaN dans la colonne Enfants par 0 enfants
df["Enfants"] = df["Enfants"].fillna(0)

print("df après remplissage des NaN dans hijos :")
print(df)
df après remplissage des NaN dans hijos :
        poids  Hauteur  Enfants  Age
Aicha      56      170      0.0   30
Ali        90      178      2.0   33
Fatima     64      165      3.0   40
Sanaa      84      187      0.0   26

6. Statistiques descriptives & visualisation¶

Avant d'entraîner un modèle, on regarde toujours la distribution et les résumés statistiques des données.

In [41]:
print("Statistiques descriptives :")
print(df.describe())
Statistiques descriptives :
           poids     Hauteur  Enfants        Age
count   4.000000    4.000000     4.00   4.000000
mean   73.500000  175.000000     1.25  32.250000
std    16.114176    9.626353     1.50   5.909033
min    56.000000  165.000000     0.00  26.000000
25%    62.000000  168.750000     0.00  29.000000
50%    74.000000  174.000000     1.00  31.500000
75%    85.500000  180.250000     2.25  34.750000
max    90.000000  187.000000     3.00  40.000000
In [43]:
# Histogramme des poids
df["poids"].hist()
plt.title("Distribution du poids")
plt.xlabel("poids (kg)")
plt.ylabel("Frequence")
plt.show()

7. Variables catégorielles → numériques (one-hot encoding)¶

Les modèles ML ne peuvent pas utiliser directement des chaînes de caractères : il faut les transformer en nombres.

In [44]:
# Exemple simple : ajouter une colonne 'sexo'
df["sex"] = ["M", "M", "F", "F"]

print("df avec colonne sexo :")
print(df)

# Encodage one-hot (une colonne par catégorie)
df_encoded = pd.get_dummies(df, columns=["sex"], drop_first=True)

print("df encodé (avec variable sex transformée) :")
print(df_encoded)
df avec colonne sexo :
        poids  Hauteur  Enfants  Age sex
Aicha      56      170      0.0   30   M
Ali        90      178      2.0   33   M
Fatima     64      165      3.0   40   F
Sanaa      84      187      0.0   26   F
df encodé (avec variable sex transformée) :
        poids  Hauteur  Enfants  Age  sex_M
Aicha      56      170      0.0   30   True
Ali        90      178      2.0   33   True
Fatima     64      165      3.0   40  False
Sanaa      84      187      0.0   26  False

8. Normalisation / standardisation d’une feature¶

Mettre les features à la même échelle aide beaucoup certains algorithmes (régression, réseaux de neurones, etc.).

In [45]:
# Normaliser la colonne 'poids' : (x - moyenne) / écart-type
peso_mean = df["poids"].mean()
peso_std = df["poids"].std()

df["poids_norm"] = (df["poids"] - peso_mean) / peso_std

print("Poids normalisé :")
print(df[["poids", "poids_norm"]])
Poids normalisé :
        poids  poids_norm
Aicha      56   -1.086000
Ali        90    1.023943
Fatima     64   -0.589543
Sanaa      84    0.651600

9. GroupBy : statistiques par groupe¶

Permet de calculer des statistiques (moyenne, écart-type, etc.) pour chaque groupe (par exemple, par sexe).

In [47]:
# Moyenne du peso par sexe
moyenne_poids_par_sex = df.groupby("sex")["poids"].mean()
print("Poids moyenne par sex :")
print(moyenne_poids_par_sex)

# Plusieurs statistiques en même temps
stats_par_sex = df.groupby("sex").agg({
    "poids": ["mean", "std"],
    "Hauteur": ["mean", "min", "max"]
})

print("Statistiques par sexe :")
print(stats_par_sex)
Poids moyenne par sex :
sex
F    74.0
M    73.0
Name: poids, dtype: float64
Statistiques par sexe :
    poids            Hauteur          
     mean        std    mean  min  max
sex                                   
F    74.0  14.142136   176.0  165  187
M    73.0  24.041631   174.0  170  178

10. Fusion de tables (merge / join)¶

En pratique, les données viennent souvent de plusieurs fichiers ou tables qu’il faut rassembler.

In [48]:
# DataFrame des informations de base
df_users = pd.DataFrame({
    "id": [1, 2, 3],
    "nombre": ["Aicha", "Ali", "Fatima"]
})

# DataFrame des achats
df_ventas = pd.DataFrame({
    "id_usuario": [1, 1, 2, 3],
    "monto": [100, 50, 200, 80]
})

# Fusion des deux tables : on relie id ↔ id_usuario
df_merged = df_users.merge(df_ventas, left_on="id", right_on="id_usuario")

print("DataFrame fusionné :")
print(df_merged)
DataFrame fusionné :
   id  nombre  id_usuario  monto
0   1   Aicha           1    100
1   1   Aicha           1     50
2   2     Ali           2    200
3   3  Fatima           3     80

11. Détection simple des outliers¶

Les valeurs très extrêmes peuvent perturber les modèles. On peut les repérer avec les quantiles.

In [49]:
# Seuil : 95e percentile du peso
seuil_haut = df["poids"].quantile(0.95)

print("Seuil haute valeur (95e percentile) :", seuil_haut)

outliers = df[df["poids"] > seuil_haut]

print("Lignes considérées comme outliers sur 'poids' :")
print(outliers)
Seuil haute valeur (95e percentile) : 89.1
Lignes considérées comme outliers sur 'poids' :
     poids  Hauteur  Enfants  Age sex  poids_norm
Ali     90      178      2.0   33   M    1.023943

12. Préparer X, y et train/test split¶

On prépare la matrice de caractéristiques X et le vecteur cible y, puis on sépare en jeu d’entraînement et de test.

In [51]:
from sklearn.model_selection import train_test_split

# Recréation d'une version encodée pour la cible
df_ml = pd.get_dummies(df, columns=["sex"], drop_first=True)

features = ["poids_norm", "Hauteur", "Age", "Enfants"]
X = df_ml[features]
y = df_ml["sex_M"]   # 1 = homme, 0 = femme (par exemple)

print("X (features) :")
print(X)

print("\ny (cible) :")
print(y)

# Découpage en train / test (80% entraînement, 20% test)
X_train, X_test, y_train, y_test = train_test_split(
    X, y, test_size=0.2, random_state=42
)

print("\nTaille X_train :", X_train.shape)
print("Taille X_test  :", X_test.shape)
X (features) :
        poids_norm  Hauteur  Age  Enfants
Aicha    -1.086000      170   30      0.0
Ali       1.023943      178   33      2.0
Fatima   -0.589543      165   40      3.0
Sanaa     0.651600      187   26      0.0

y (cible) :
Aicha      True
Ali        True
Fatima    False
Sanaa     False
Name: sex_M, dtype: bool

Taille X_train : (3, 4)
Taille X_test  : (1, 4)

13. Mini-projet (à faire)¶

  1. Charger un fichier CSV réel (pd.read_csv(...))
  2. Afficher head(), info(), describe()
  3. Vérifier et traiter les NaN (isna(), dropna(), fillna())
  4. Si nécessaire, encoder les colonnes catégorielles (get_dummies)
  5. Créer au moins 2 nouvelles features (colonnes calculées)
  6. Visualiser au moins 2 distributions (histogrammes)
  7. Utiliser groupby pour comparer deux groupes (ex : hommes/femmes, ville, classe)
  8. Préparer X et y
  9. Faire un train_test_split
  10. Écrire une mini conclusion sur l’état du dataset (propre ? outliers ? colonnes importantes ?).

14. Réflexion finale (à rédiger)¶

En quelques phrases, explique :

  • ce que tu as appris avec Pandas dans ce TP ;
  • pourquoi Pandas est indispensable avant d’appliquer un algorithme de Machine Learning ;
  • quelles fonctions/parties tu penses réutiliser le plus souvent.

Rédiger votre réponse ci-dessous en Markdown.


© Pr El Alam — Cours ML — Séance de TP12 : Pandas 🐼