Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 33

Array Indexing and Slicing

Recommended resources

Bonjour ! Dans la leçon précédente, nous avons découvert comment créer des tableaux NumPy, la structure de données fondamentale pour le calcul numérique. Vous savez maintenant générer des tableaux à partir de listes Python ou avec des fonctions pratiques comme np.arange et np.linspace.

Aujourd'hui, nous allons apprendre à interagir avec ces tableaux. L'objectif de cette leçon est de vous montrer comment accéder à des éléments spécifiques et à des sous-ensembles de données, puis comment les modifier. Nous utiliserons pour cela deux techniques essentielles : l'indexation (indexing) et le découpage (slicing). Maîtriser ces opérations est absolument fondamental, car en machine learning, vous passerez votre temps à sélectionner des caractéristiques (colonnes), des échantillons (lignes) ou à diviser vos données en ensembles d'entraînement et de test.

1. L'indexation : Accéder à des Éléments Individuels

Tout comme pour les listes Python, l'indexation dans NumPy est basée sur un indice de départ à 0. Pour accéder à un élément, vous utilisez des crochets [] en spécifiant la position de l'élément souhaité.

L'article suivant, "How to Index, Slice and Reshape NumPy Arrays", est une excellente ressource en anglais qui couvre précisément ce sujet. Nous allons le parcourir par étapes.

How to Index, Slice and Reshape NumPy Arrays for ...

Cet article de Machine Learning Mastery explique clairement les bases de l'indexation pour les tableaux à une et deux dimensions.

Lisez les sections "One-Dimensional Indexing" et "Two-Dimensional Indexing". Concentrez-vous sur la syntaxe pour les tableaux 1D et 2D.

Indexation en 1D

Pour un tableau à une dimension (un vecteur), le fonctionnement est identique à celui d'une liste :

  • mon_tableau[0] donne le premier élément.
  • mon_tableau[2] donne le troisième élément.
  • L'indexation négative fonctionne aussi : mon_tableau[-1] donne le dernier élément.
import numpy as np




# Créons un tableau de 10 à 50 par pas de 10
v = np.arange(10, 51, 10)
print(f"Tableau original : {v}") # Affiche [10 20 30 40 50]




# Accéder au premier élément
print(f"Premier élément v[0] : {v[0]}") # Affiche 10




# Accéder au dernier élément
print(f"Dernier élément v[-1] : {v[-1]}") # Affiche 50

Indexation en 2D

Pour les tableaux à deux dimensions (matrices), votre expérience en algèbre linéaire vous sera utile. On pense en termes de lignes et de colonnes. Pour sélectionner un élément, on utilise la syntaxe tableau[ligne, colonne].




# Créons une matrice 3x4
matrice = np.array([
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
])
print("Matrice originale :\n", matrice)




# Accéder à l'élément à la ligne 0, colonne 2 (c'est le nombre 3)
element = matrice[0, 2]
print(f"\nÉlément à la position [0, 2] : {element}")




# Accéder à l'élément à la ligne 2, colonne 3 (c'est le nombre 12)
element_fin = matrice[2, 3]
print(f"Élément à la position [2, 3] : {element_fin}")

La syntaxe matrice[ligne, colonne] est la méthode privilégiée et la plus claire en NumPy.


2. Le Slicing : Sélectionner des Sous-Tableaux

L'indexation permet de récupérer un seul élément. Le slicing (découpage) permet d'en extraire toute une section. La syntaxe est la même que pour les listes Python : start:stop:step. Rappelez-vous que l'indice start est inclus et l'indice stop est exclu.

NumPy Array Indexing and Slicing - ApX Machine Learning

Ce guide d'ApX Machine Learning propose des exemples très clairs et bien expliqués sur le slicing en 1D et 2D.

Lisez attentivement la section "Slicing Arrays", en particulier les sous-sections "One-Dimensional Array Slicing" et "Two-Dimensional Array Slicing". Notez bien comment le symbole : est utilisé pour sélectionner toutes les lignes ou toutes les colonnes.

Slicing en 1D

Voici les cas d'usage les plus courants :

  • v[1:4] : prend les éléments de l'indice 1 à 3 (l'indice 4 est exclu).
  • v[:3] : prend les éléments du début jusqu'à l'indice 2.
  • v[2:] : prend les éléments de l'indice 2 jusqu'à la fin.
  • v[::2] : prend un élément sur deux sur tout le tableau.
v = np.arange(10, 20) # Tableau [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]




# Éléments de l'indice 2 à 5 (exclu)
sous_tableau = v[2:5]
print(f"v[2:5] -> {sous_tableau}") # Affiche [12 13 14]




# Tous les éléments depuis l'indice 6
fin_tableau = v[6:]
print(f"v[6:] -> {fin_tableau}") # Affiche [16 17 18 19]

Slicing en 2D

C'est ici que le slicing devient vraiment puissant pour la manipulation de données. On applique la même logique start:stop pour les lignes et les colonnes, en les séparant par une virgule : matrice[slice_lignes, slice_colonnes].

L'image ci-dessous illustre parfaitement plusieurs opérations de slicing sur un tableau 2D.

Exemples d'opérations d'indexation et de slicing sur un tableau NumPy 2D. Observez la correspondance entre le code à gauche et les sélections colorées dans le tableau à droite. Par exemple, `a[0, 3:5]` sélectionne la première ligne (indice 0) et les colonnes d'indice 3 et 4.

Utilisons notre matrice précédente pour illustrer :

matrice = np.array([
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 10, 11, 12]
])




# Sélectionner toute la première ligne (indice 0)
premiere_ligne = matrice[0, :] # Le ':' signifie 'toutes les colonnes'
print(f"Première ligne :\n{premiere_ligne}\n")




# Sélectionner la deuxième colonne (indice 1)
deuxieme_colonne = matrice[:, 1] # Le ':' signifie 'toutes les lignes'
print(f"Deuxième colonne :\n{deuxieme_colonne}\n")




# Sélectionner un sous-tableau : les deux premières lignes et les colonnes d'indice 1 à 2
sous_matrice = matrice[0:2, 1:3]
print(f"Sous-matrice 2x2 :\n{sous_matrice}")

Cette technique est fondamentale en machine learning. Par exemple, pour séparer les "features" (les variables d'entrée, X) de la cible (la variable de sortie, y) :

How to Index, Slice and Reshape NumPy Arrays for ...

Retournons à l'article de Machine Learning Mastery pour voir des applications pratiques du slicing.

Lisez la section "Two-Dimensional Slicing". Elle montre deux exemples très concrets : séparer les données d'entrée (X) de la sortie (y), et diviser un dataset en un ensemble d'entraînement et de test.


3. Modifier les Éléments et la Notion de Vue vs Copie

On peut non seulement lire les données, mais aussi les modifier en utilisant les mêmes syntaxes d'indexation et de slicing.

v = np.arange(5) # [0 1 2 3 4]
print(f"Avant modification : {v}")




# Modifier un seul élément
v[2] = 99
print(f"Après modification simple : {v}") # [0 1 99 3 4]




# Modifier une tranche (slice)
v[0:2] = -1 # Remplace les éléments aux indices 0 et 1 par -1
print(f"Après modification de slice : {v}") # [-1 -1 99 3 4]

Attention : Vues et Copies

C'est un point crucial et une source d'erreurs courante pour les débutants. Par défaut, le slicing d'un tableau NumPy crée une vue (view), et non une copie (copy). Une vue est une "fenêtre" sur les données originales. Si vous modifiez la vue, vous modifiez également le tableau original !

NumPy Array Indexing and Slicing - ApX Machine Learning

La distinction entre une vue et une copie est fondamentale. Ce passage de l'article d'ApX l'explique parfaitement.

Lisez la section "Important: Views vs. Copies". Assurez-vous de bien comprendre la différence de comportement entre une modification sur une vue et sur une copie créée avec .copy().

Voyons cela en action :




# 1. Comportement avec une VUE (comportement par défaut)
original = np.arange(10, 60, 10) # [10 20 30 40 50]
print(f"Tableau original : {original}")

vue = original[1:4] # Crée une vue sur [20 30 40]
print(f"Vue extraite : {vue}")




# Modifions un élément de la vue
vue[1] = 300 # On modifie le 30 en 300
print(f"Vue modifiée : {vue}")




# Regardons le tableau original... il a changé !
print(f"Tableau original APRÈS modification de la vue : {original}") # Affiche [10 20 300 40 50]

NumPy fait cela pour des raisons de performance : sur des très grands tableaux de données, éviter de dupliquer la mémoire est beaucoup plus efficace.

Si vous avez besoin d'une copie indépendante pour ne pas affecter le tableau original, vous devez utiliser la méthode .copy().




# 2. Comportement avec une COPIE
original = np.arange(10, 60, 10) # [10 20 30 40 50]
copie = original[1:4].copy() # On demande explicitement une copie




# Modifions la copie
copie[1] = 300




# Le tableau original reste intact
print(f"Tableau original APRÈS modification de la copie : {original}") # Affiche [10 20 30 40 50]

Si vous préférez un résumé en vidéo et en arabe, la chaîne Elzero Web School que vous appréciez a une excellente vidéo sur le sujet.

Learn Python in Arabic #146 - Numpy - Array Slicing

Cette vidéo d'Elzero Web School couvre en arabe les techniques de slicing que nous venons de voir.

Regardez-la pour consolider votre compréhension des différentes manières de découper les tableaux en 1D et 2D.


Exercices Pratiques

  1. Exercice 1 : Sélection

    • Créez une matrice 4x4 avec np.arange(16).reshape(4, 4).
    • Sélectionnez et affichez l'élément à la ligne 2, colonne 3.
    • Sélectionnez et affichez la troisième ligne complète (indice 2).
    • Sélectionnez et affichez la première colonne complète (indice 0).
  2. Exercice 2 : Slicing

    • En utilisant la même matrice 4x4 de l'exercice 1.
    • Extrayez et affichez la sous-matrice 2x2 située en bas à droite.
    • Extrayez et affichez les deux colonnes du milieu.
  3. Exercice 3 : Vue vs Copie

    • Créez un tableau a = np.arange(10).
    • Créez une vue b = a[3:7].
    • Modifiez le premier élément de b en lui assignant la valeur 100.
    • Affichez b et a. Qu'observez-vous ?
    • Répétez l'opération, mais cette fois en créant une copie c = a[3:7].copy(). Modifiez c et vérifiez que a n'a pas changé.

Solutions

Solution de l'exercice 1 :

import numpy as np

mat = np.arange(16).reshape(4, 4)
print("Matrice de base :\n", mat)




# Élément à la ligne 2, colonne 3
elem = mat[2, 3]
print("\nÉlément [2, 3] :", elem)




# Troisième ligne
ligne_2 = mat[2, :]
print("\nTroisième ligne :", ligne_2)




# Première colonne
col_0 = mat[:, 0]
print("\nPremière colonne :", col_0)

Solution de l'exercice 2 :

import numpy as np

mat = np.arange(16).reshape(4, 4)
print("Matrice de base :\n", mat)




# Sous-matrice 2x2 en bas à droite (lignes 2 et 3, colonnes 2 et 3)
bas_droite = mat[2:, 2:]
print("\nSous-matrice en bas à droite :\n", bas_droite)




# Colonnes du milieu (indices 1 et 2)
cols_milieu = mat[:, 1:3]
print("\nColonnes du milieu :\n", cols_milieu)

Solution de l'exercice 3 :

import numpy as np

a = np.arange(10)
print(f"Original 'a': {a}")




# Avec une vue
b = a[3:7]
b[0] = 100
print(f"Vue 'b' modifiée: {b}")
print(f"'a' après modif de la vue 'b': {a}") # 'a' est modifié




# Avec une copie
a = np.arange(10) # Réinitialisation de 'a'
c = a[3:7].copy()
c[0] = 100
print(f"\nCopie 'c' modifiée: {c}")
print(f"'a' après modif de la copie 'c': {a}") # 'a' est inchangé

Conclusion

Félicitations ! Vous savez maintenant comment naviguer à l'intérieur des tableaux NumPy. C'est une compétence que vous utiliserez constamment.

Points clés à retenir :

  • L'indexation permet d'accéder à un élément unique avec la syntaxe tableau[ligne, colonne].
  • Le slicing permet d'extraire des sous-tableaux avec la syntaxe tableau[start:stop, start:stop].
  • Le symbole : seul est un joker pour "tous les éléments" sur un axe donné.
  • Par défaut, le slicing crée une vue qui est liée au tableau original. Les modifications sur la vue affectent l'original.
  • Utilisez la méthode .copy() pour obtenir une copie indépendante et éviter de modifier le tableau d'origine.

Maintenant que nous savons créer, sélectionner et modifier des données dans les tableaux, la prochaine leçon portera sur ce qui rend NumPy si puissant : réaliser des opérations mathématiques et statistiques sur des tableaux entiers de manière vectorisée. C'est là que vous verrez l'efficacité de NumPy en action.