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.
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)
Une Series est comme une colonne de données, avec un index (les étiquettes de lignes).
# 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
# 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
# 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
Un DataFrame est un tableau 2D (lignes × colonnes), très utilisé pour représenter un dataset en Machine Learning.
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
# 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
# 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
Les filtres permettent de sélectionner uniquement les lignes qui respectent une condition (par exemple, poids > 80).
# 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
# 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
Ajouter, modifier ou supprimer des colonnes est très fréquent lorsqu’on prépare un dataset pour le Machine Learning.
# 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
# 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
# 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
Les modèles de Machine Learning ne supportent pas les valeurs manquantes : il faut les détecter et les traiter.
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
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
# 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
Avant d'entraîner un modèle, on regarde toujours la distribution et les résumés statistiques des données.
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
# Histogramme des poids
df["poids"].hist()
plt.title("Distribution du poids")
plt.xlabel("poids (kg)")
plt.ylabel("Frequence")
plt.show()
Les modèles ML ne peuvent pas utiliser directement des chaînes de caractères : il faut les transformer en nombres.
# 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
Mettre les features à la même échelle aide beaucoup certains algorithmes (régression, réseaux de neurones, etc.).
# 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
Permet de calculer des statistiques (moyenne, écart-type, etc.) pour chaque groupe (par exemple, par sexe).
# 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
En pratique, les données viennent souvent de plusieurs fichiers ou tables qu’il faut rassembler.
# 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
Les valeurs très extrêmes peuvent perturber les modèles. On peut les repérer avec les quantiles.
# 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
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.
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)
pd.read_csv(...)) head(), info(), describe() isna(), dropna(), fillna()) get_dummies) train_test_split En quelques phrases, explique :
Rédiger votre réponse ci-dessous en Markdown.
© Pr El Alam — Cours ML — Séance de TP12 : Pandas 🐼