TP 11 — NumPy pour le Machine Learning¶

Matière : Machine Learning
Enseignant : Pr El Alami Hassoun Mohamed
Séance : TP 1.1 — NumPy
Durée : 1h30

Nom de l'étudiant : à compléter

Objectif : découvrir et pratiquer les bases de NumPy, des tableaux simples jusqu’aux opérations utilisées en Machine Learning.

0. Importation de NumPy¶

Dans tout ce TP, nous utiliserons NumPy, la bibliothèque de base pour le calcul scientifique en Python.

In [25]:
import numpy as np

# (optionnel) : pour afficher les nombres avec moins de décimales
np.set_printoptions(precision=3)
print(np.random.rand(8))
[0.609 0.857 0.996 0.698 0.625 0.968 0.313 0.924]

1. Création de tableaux NumPy (bases)¶

Un tableau NumPy (ndarray) est la structure de données de base utilisée en Machine Learning :

  • plus rapide que les listes Python
  • tous les éléments sont du même type
  • très efficace pour les opérations mathématiques vectorisées.

1.1 Tableau 1D des 10 premiers entiers¶

In [26]:
# TODO : créer un tableau contenant les entiers de 0 à 9
# Utiliser np.arange
# Rappel : np.arange(n) renvoie [0, 1, ..., n-1]

tableau_1d = np.arange(10)
print("Tableau 1D :", tableau_1d)
print("Type de l'objet :", type(tableau_1d))
Tableau 1D : [0 1 2 3 4 5 6 7 8 9]
Type de l'objet : <class 'numpy.ndarray'>

1.2 Matrice 3×3 de nombres aléatoires¶

In [9]:
# np.random.rand(3, 3) crée un tableau 2D de taille (3, 3)
# avec des valeurs aléatoires entre 0 et 1.

tableau_2d = np.random.rand(3, 3)
print("Matrice 3x3 aléatoire :")
print(tableau_2d)
Matrice 3x3 aléatoire :
[[0.597 0.104 0.479]
 [0.592 0.692 0.049]
 [0.048 0.146 0.664]]

1.3 Tableaux de zéros, de uns et séquences simples¶

In [27]:
# Tableau de zéros 4x5
tableau_zeros = np.zeros((4, 5))
print("Tableau de zéros (4x5) :")
print(tableau_zeros)

# Tableau de uns 3x2
tableau_uns = np.ones((3, 2))
print("\nTableau de uns (3x2) :")
print(tableau_uns)

# Carrés de 0 à 9 (opération vectorisée)
tableau_carres = np.arange(10) ** 2
print("\nCarrés de 0 à 9 :")
print(tableau_carres)

# Séquence de 10 à 50 avec un pas de 5
tableau_sequence = np.arange(10, 51, 5)
print("\nSéquence 10 → 50 (pas de 5) :")
print(tableau_sequence)
Tableau de zéros (4x5) :
[[0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]
 [0. 0. 0. 0. 0.]]

Tableau de uns (3x2) :
[[1. 1.]
 [1. 1.]
 [1. 1.]]

Carrés de 0 à 9 :
[ 0  1  4  9 16 25 36 49 64 81]

Séquence 10 → 50 (pas de 5) :
[10 15 20 25 30 35 40 45 50]

2. Propriétés des tableaux (shape, dtype, …)¶

Ces propriétés sont cruciales en Machine Learning, car les modèles attendent des formes précises.

In [10]:
print("Nombre de dimensions (ndim) :", tableau_2d.ndim)
print("Forme (shape) :", tableau_2d.shape)
print("Taille totale (size) :", tableau_2d.size)
print("Type des éléments (dtype) :", tableau_2d.dtype)
Nombre de dimensions (ndim) : 2
Forme (shape) : (3, 3)
Taille totale (size) : 9
Type des éléments (dtype) : float64

2.1 Conversion de type¶

In [11]:
# En ML, on travaille presque toujours en float (valeurs réelles).
tableau_float = np.array([1, 2, 3, 4, 5], dtype=float)
print("Tableau float :", tableau_float)
print("dtype :", tableau_float.dtype)

print("Maximum :", tableau_float.max())
print("Minimum :", tableau_float.min())
Tableau float : [1. 2. 3. 4. 5.]
dtype : float64
Maximum : 5.0
Minimum : 1.0

3. Indexation et slicing¶

L’indexation et le slicing permettent d’extraire des sous-parties d’un tableau :

  • sélectionner des lignes / colonnes
  • découper un batch de données
  • manipuler des features.

3.1 Indexation simple sur un tableau 1D¶

In [12]:
print("Tableau 1D :", tableau_1d)

# Accès au 2e élément (index 1, car on commence à 0)
print("Deuxième élément :", tableau_1d[1])

# Slicing : éléments d'index 2 à 5 (5 non inclus)
print("Slicing (indices 2 à 5) :", tableau_1d[2:6])
Tableau 1D : [0 1 2 3 4 5 6 7 8 9]
Deuxième élément : 1
Slicing (indices 2 à 5) : [2 3 4 5]

3.2 Indexation 2D (lignes, colonnes, sous-matrices)¶

In [30]:
print("Matrice 3x3 :")
print(tableau_2d)

# Élément en (1, 1)
print("\nÉlément (1,1) :", tableau_2d[1, 1])

# Ligne 1 complète
print("Ligne 1 complète :", tableau_2d[1, :])

# Deux premières lignes et les trois colonnes
print("\nSous-matrice (2 premières lignes, 3 colonnes) :")
print(tableau_2d[:2, :3])
Matrice 3x3 :
[[0.597 0.104 0.479]
 [0.592 0.692 0.049]
 [0.048 0.146 0.664]]

Élément (1,1) : 0.6922150718494621
Ligne 1 complète : [0.592 0.692 0.049]

Sous-matrice (2 premières lignes, 3 colonnes) :
[[0.597 0.104 0.479]
 [0.592 0.692 0.049]]

3.3 Inverser un tableau¶

In [17]:
# np.arange(10) crée [0 1 2 3 4 5 6 7 8 9]
indices = np.arange(10)
indices_inverse = indices[::-1]

print("Indices :", indices)
print("Indices inversés :", indices_inverse)
Indices : [0 1 2 3 4 5 6 7 8 9]
Indices inversés : [9 8 7 6 5 4 3 2 1 0]

4. Opérations sur les tableaux¶

NumPy applique les opérations élément par élément :
c’est la base des calculs vectorisés utilisés en Machine Learning (fonctions de coût, gradients, etc.).

In [14]:
# Deux tableaux aléatoires 1D de taille 5
tableau_a = np.random.rand(5)
tableau_b = np.random.rand(5)

print("Tableau A :", tableau_a)
print("Tableau B :", tableau_b)

addition = tableau_a + tableau_b
soustraction = tableau_a - tableau_b
multiplication = tableau_a * tableau_b
division = tableau_a / tableau_b

print("\nAddition :", addition)
print("Soustraction :", soustraction)
print("Multiplication :", multiplication)
print("Division :", division)
Tableau A : [1.    0.492 0.508 0.187 0.592]
Tableau B : [0.226 0.293 0.485 0.411 0.713]

Addition : [1.226 0.785 0.993 0.599 1.305]
Soustraction : [ 0.774  0.199  0.023 -0.224 -0.12 ]
Multiplication : [0.226 0.144 0.246 0.077 0.422]
Division : [4.419 1.679 1.047 0.456 0.831]

4.1 Statistiques simples¶

In [15]:
somme_total = tableau_a.sum()
moyenne = tableau_a.mean()
ecart_type = tableau_a.std()
produit_total = tableau_a.prod()

print("Somme :", somme_total)
print("Moyenne :", moyenne)
print("Écart type :", ecart_type)
print("Produit :", produit_total)
Somme : 2.7794180733152465
Moyenne : 0.5558836146630493
Écart type : 0.26103532093187665
Produit : 0.027729697307867823

5. Manipulations avancées : reshape, concat, empilement, conditions¶

Ces opérations servent à restructurer les données, très utile pour préparer des inputs de modèles ML.

5.1 Changer la forme d’un tableau (reshape)¶

In [16]:
# Création d'un tableau 1D de 12 éléments
base = np.arange(12)
print("Base 1D :", base)

# Reshape en matrice 3x4
tableau_reshape = base.reshape((3, 4))
print("\nTableau reshape (3x4) :")
print(tableau_reshape)
Base 1D : [ 0  1  2  3  4  5  6  7  8  9 10 11]

Tableau reshape (3x4) :
[[ 0  1  2  3]
 [ 4  5  6  7]
 [ 8  9 10 11]]

5.2 Concaténer deux tableaux 1D¶

In [17]:
tableau_concat = np.concatenate((tableau_a, tableau_b))
print("Tableau concaténé :", tableau_concat)
Tableau concaténé : [1.    0.492 0.508 0.187 0.592 0.226 0.293 0.485 0.411 0.713]

5.3 Empilement vertical et horizontal¶

In [18]:
matrice_a = np.array([[1, 2], [3, 4]])
matrice_b = np.array([[5, 6], [7, 8]])
print(matrice_a)
empile_verticale = np.vstack((matrice_a, matrice_b))
empile_horizontale = np.hstack((matrice_a, matrice_b))

print("Empilement vertical :")
print(empile_verticale)

print("\nEmpilement horizontal :")
print(empile_horizontale)
Empilement vertical :
[[1 2]
 [3 4]
 [5 6]
 [7 8]]

Empilement horizontal :
[[1 2 5 6]
 [3 4 7 8]]

5.4 Utiliser np.where pour créer un tableau binaire¶

In [19]:
# On transforme tableau_a en tableau binaire :
# 1 si valeur > 0.5, 0 sinon.
tableau_binaire = np.where(tableau_a > 0.5, 1, 0)
print("Tableau A :", tableau_a)
print("Tableau binaire (A > 0.5) :", tableau_binaire)
Tableau A : [1.    0.492 0.508 0.187 0.592]
Tableau binaire (A > 0.5) : [1 0 1 0 1]

6. Algèbre linéaire avec NumPy¶

Les modèles de Machine Learning reposent fortement sur l’algèbre linéaire :
produits matriciels, déterminants, valeurs propres, SVD, etc.

In [20]:
# Deux matrices 2x2
matrice_1 = np.array([[1, 2],
                      [3, 4]])
matrice_2 = np.array([[5, 6],
                      [7, 8]])

# Produit matriciel (attention : ce n'est PAS une multiplication élément par élément)
produit_matriciel = np.dot(matrice_1, matrice_2)
print("Produit matriciel :")
print(produit_matriciel)
Produit matriciel :
[[19 22]
 [43 50]]
In [21]:
# Déterminant d'une matrice 2x2
matrice = np.array([[1, 2],
                    [3, 4]])

determinant = np.linalg.det(matrice)
print("Déterminant de la matrice :", determinant)
Déterminant de la matrice : -2.0000000000000004
In [22]:
# Valeurs propres et vecteurs propres d'une matrice 3x3
matrice_3x3 = np.array([[1, 2, 3],
                        [0, 1, 4],
                        [5, 6, 0]])

valeurs_propres, vecteurs_propres = np.linalg.eig(matrice_3x3)
print("Valeurs propres :")
print(valeurs_propres)
print("\nVecteurs propres :")
print(vecteurs_propres)
Valeurs propres :
[-5.23  -0.026  7.256]

Vecteurs propres :
[[ 0.226 -0.758 -0.499]
 [ 0.526  0.632 -0.467]
 [-0.82  -0.162 -0.73 ]]
In [ ]:
# Décomposition en valeurs singulières (SVD)(La SVD permet de résumer une matrice complexe en ses directions les plus importantes.)
#Parce que la SVD est utilisée dans :
#PCA (analyse en composantes principales)
#Réduction de dimension
#Compression d’images
#Reconstruction d’une matrice
#Systèmes de recommandation
#La SVD décompose une matrice en trois parties :
# U : les directions dans l’espace des lignes
# S : l’importance de chaque direction
# Vt : les directions dans l’espace des colonnes
# Cela permet de comprendre la structure d’une matrice, de réduire sa dimension ou de comprimer des données.
matrice_svd = np.array([[1, 2],
                        [3, 4],
                        [5, 6]])

U, S, Vt = np.linalg.svd(matrice_svd)
print("Matrice U :")
print(U)
print("\nValeurs singulières S :")
print(S)
print("\nMatrice Vt :")
print(Vt)

7. Mini-projet : Chargement et analyse d’un CSV¶

Dans cette partie, nous allons :

  1. Charger un fichier CSV avec pandas
  2. Faire une analyse exploratoire rapide
  3. Visualiser les données
  4. Appliquer un filtre conditionnel.

Remplacer "data.csv" par le nom réel de votre fichier.

In [ ]:
import pandas as pd

# Charger le fichier CSV (à adapter)
# Exemple : df = pd.read_csv("mon_fichier.csv")
df = pd.read_csv("data.csv")

print("Aperçu des données :")
print(df.head())
In [ ]:
print("Statistiques descriptives :")
print(df.describe())
In [ ]:
import matplotlib.pyplot as plt

# Histogrammes de toutes les colonnes numériques
df.hist()
plt.tight_layout()
plt.show()
In [ ]:
# Exemple de filtre : garder les lignes où une colonne est > à un seuil
# À adapter : remplacer 'column_name' et 'seuil' par des valeurs pertinentes

column_name = "column_name"  # à modifier
seuil = 0                    # à modifier

filtre = df[df[column_name] > seuil]
print("Lignes filtrées :")
print(filtre.head())

8. Modules essentiels pour le Machine Learning avec NumPy¶

Dans cette section, on relie NumPy directement au Machine Learning :

  • broadcasting
  • vectorisation et MSE
  • gestion des valeurs manquantes (NaN)
  • matrice de caractéristiques (X) et labels (y)
  • mini descente de gradient.

8.1 Broadcasting : normalisation des features¶

In [ ]:
# Matrice de données : 2 exemples, 3 caractéristiques
X = np.array([[1, 2, 3],
              [4, 5, 6]])

# Moyenne par colonne (par feature)
mean = X.mean(axis=0)
print("Moyenne par feature :", mean)

# Broadcasting : X - mean
# NumPy "étend" automatiquement le vecteur mean sur les lignes de X.
X_normalized = X - mean

print("\nDonnées normalisées :")
print(X_normalized)

8.2 Vectorisation : calcul du MSE (Mean Squared Error)¶

In [ ]:
# Vecteurs des valeurs vraies et prédites
y_true = np.array([1, 2, 3])
y_pred = np.array([1.2, 1.9, 3.1])

# Erreurs point par point
erreurs = y_true - y_pred
print("Erreurs :", erreurs)

# MSE vectorisé : moyenne des carrés des erreurs
mse = (erreurs ** 2).mean()
print("Erreur quadratique moyenne (MSE) :", mse)

8.3 Données manquantes : gestion des NaN¶

In [ ]:
X_nan = np.array([1, np.nan, 3, np.nan, 5])
print("Données avec NaN :", X_nan)

# np.nanmean ignore automatiquement les NaN
moyenne_sans_nan = np.nanmean(X_nan)
print("Moyenne en ignorant les NaN :", moyenne_sans_nan)

8.4 Organisation des données : X (features) et y (labels)¶

In [ ]:
# 3 exemples, 2 caractéristiques (par ex. taille, poids)
X = np.array([[5.1, 3.5],
              [4.9, 3.0],
              [6.2, 2.8]])

# Labels associés (par ex. 0 = classe A, 1 = classe B)
y = np.array([0, 0, 1])

print("X = matrice de caractéristiques :")
print(X)
print("Shape de X :", X.shape)

print("\ny = vecteur de labels :")
print(y)
print("Shape de y :", y.shape)

8.5 Mini descente de gradient pour une régression linéaire simple¶

In [ ]:
# Objectif : apprendre w dans le modèle y ≈ w * x
# Données simples : y = 2 * x
x = np.array([1, 2, 3])
y = np.array([2, 4, 6])

# Paramètre du modèle (poids), initialisé à 0
w = 0.0

# Taux d'apprentissage
alpha = 0.1

print("Poids initial w :", w)

for i in range(50):
    # Prédiction du modèle
    y_pred = w * x

    # Gradient de la MSE par rapport à w
    # d/dw MSE = mean( 2 * (w*x - y) * x )
    gradient = ((y_pred - y) * x).mean()

    # Mise à jour du paramètre
    w -= alpha * gradient

    # Affichage toutes les 10 itérations
    if i % 10 == 0:
        mse = ((y_pred - y) ** 2).mean()
        print(f"Iteration {i:2d} | w = {w:.4f} | MSE = {mse:.4f}")

print("\nPoids final appris w ≈", w)


© Pr El Alam — Cours ML — Séance de TP 11 : NumPy