Introduction aux Fonctions Universelles NumPy

NumPyBeginner
Pratiquer maintenant

Introduction

Dans ce laboratoire, vous apprendrez les bases des fonctions universelles (Universal Functions) de NumPy, communément appelées ufuncs. Les ufuncs sont une pierre angulaire du calcul haute performance en Python, vous permettant d'effectuer des opérations rapides, élément par élément, sur des tableaux de données entiers. Nous aborderons l'arithmétique de base, le concept puissant de broadcasting, les méthodes d'agrégation, et comment contrôler les types de données de vos résultats. À la fin de ce laboratoire, vous serez capable d'utiliser les ufuncs pour écrire du code de traitement de données plus propre et plus efficace.

Ceci est un Guided Lab, qui fournit des instructions étape par étape pour vous aider à apprendre et à pratiquer. Suivez attentivement les instructions pour compléter chaque étape et acquérir une expérience pratique. Les données historiques montrent que c'est un laboratoire de niveau débutant avec un taux de réussite de 89%. Il a reçu un taux d'avis positifs de 100% de la part des apprenants.

Arithmétique de Base avec les Ufuncs

À la base, les ufuncs effectuent des opérations élément par élément. Cela signifie que lorsque vous appliquez une opération à deux tableaux, l'opération est effectuée sur chaque paire d'éléments correspondants. Les ufuncs les plus courantes sont les opérateurs arithmétiques standard tels que +, -, *, et /.

Commençons par effectuer une addition simple sur deux tableaux NumPy.

Tout d'abord, ouvrez le fichier ufunc_examples.py depuis l'explorateur de fichiers à gauche. Remplacez le contenu existant par le code suivant. Ce code importe NumPy, crée deux tableaux et les additionne.

import numpy as np

## Create two arrays
arr1 = np.array([0, 2, 3, 4])
arr2 = np.array([1, 1, -1, 2])

## The '+' operator is a ufunc that adds the arrays element-wise
result = arr1 + arr2

## Print the result
print("Step 1 Result:")
print(result)

Après avoir ajouté le code, enregistrez le fichier. Exécutez ensuite le script depuis le terminal pour voir la sortie.

python ufunc_examples.py

Vous devriez voir le résultat de l'addition élément par élément.

Step 1 Result:
[1 3 2 6]

Ceci démontre le comportement fondamental d'une ufunc : arr1[0] est ajouté à arr2[0], arr1[1] à arr2[1], et ainsi de suite, produisant un nouveau tableau avec les résultats.

Le Broadcasting en Action

Le broadcasting est un mécanisme puissant qui permet à NumPy de travailler avec des tableaux de formes différentes lors des opérations arithmétiques. En coulisses, NumPy "diffuse" (broadcasts) le tableau le plus petit sur le tableau le plus grand afin qu'ils aient des formes compatibles.

Un exemple courant est la multiplication de chaque élément d'un tableau par un seul nombre. Voyons également un cas plus complexe où un tableau 1D est diffusé sur un tableau 2D.

Modifiez votre fichier ufunc_examples.py. Ajoutez le code suivant à la fin du script.

## --- Appended code for Step 2 ---

## Broadcasting a scalar to an array
arr1 = np.array([1, 2, 3])
scalar_result = arr1 * 10
print("\nStep 2 Result (Scalar Broadcast):")
print(scalar_result)

## Broadcasting a 1D array to a 2D array
arr2d = np.array([[1], [2], [3]]) ## Shape (3, 1)
arr1d = np.array([1, 2, 3])      ## Shape (3,)
broadcast_result = arr2d * arr1d
print("\nStep 2 Result (Array Broadcast):")
print(broadcast_result)

Enregistrez le fichier et exécutez-le à nouveau depuis le terminal.

python ufunc_examples.py

Vous verrez la sortie pour les étapes 1 et 2.

Step 1 Result:
[1 3 2 6]

Step 2 Result (Scalar Broadcast):
[10 20 30]

Step 2 Result (Array Broadcast):
[[1 2 3]
 [2 4 6]
 [3 6 9]]

Dans le second exemple, le tableau 1D arr1d (forme (3,)) et le tableau 2D arr2d (forme (3, 1)) sont diffusés ensemble vers une forme commune de (3, 3) avant que la multiplication élément par élément ne se produise.

Agrégation de Tableaux avec .reduce()

Outre les opérations élément par élément, les ufuncs disposent de méthodes spéciales pour effectuer des agrégations. La méthode .reduce() est l'une des plus utiles. Elle applique une ufunc de manière répétée le long d'un axe spécifié d'un tableau jusqu'à ce qu'il ne reste qu'une seule dimension.

Par exemple, np.add.reduce(arr) est équivalent à np.sum(arr). Voyons comment cela fonctionne sur un tableau 2D.

Ajoutez le code suivant à votre fichier ufunc_examples.py.

## --- Appended code for Step 3 ---

## Create a 3x3 array
arr = np.arange(9).reshape(3, 3)
print("\nStep 3 Original Array:")
print(arr)

## Reduce the array by summing along axis 1 (the columns)
## This will sum the elements in each row.
## For row 0: 0 + 1 + 2 = 3
## For row 1: 3 + 4 + 5 = 12
## For row 2: 6 + 7 + 8 = 21
reduced_result = np.add.reduce(arr, axis=1)

print("\nStep 3 Result (reduce on axis=1):")
print(reduced_result)

Enregistrez le fichier et exécutez-le.

python ufunc_examples.py

La sortie inclura désormais les résultats de cette étape.

... (previous output) ...

Step 3 Original Array:
[[0 1 2]
 [3 4 5]
 [6 7 8]]

Step 3 Result (reduce on axis=1):
[ 3 12 21]

Comme vous pouvez le constater, .reduce() a réduit le tableau le long de l'axe spécifié en appliquant l'opération add à ses éléments.

Spécification des Types de Données de Sortie

NumPy détermine généralement le type de données du tableau de sortie automatiquement. Cependant, vous pouvez spécifier explicitement le type de données de sortie en utilisant l'argument dtype. Ceci est utile pour contrôler l'utilisation de la mémoire ou garantir la précision numérique.

Effectuons une réduction en utilisant la multiplication et en forçant la sortie à être un nombre à virgule flottante, même si l'entrée est un tableau d'entiers.

Ajoutez le code suivant à la fin de ufunc_examples.py.

## --- Appended code for Step 4 ---

## Use the same 3x3 array from Step 3
arr = np.arange(1, 10).reshape(3, 3) ## Using 1-9 to avoid multiplying by zero
print("\nStep 4 Original Array:")
print(arr)

## Reduce with multiplication, casting the output to float
## For row 0: 1 * 2 * 3 = 6
## For row 1: 4 * 5 * 6 = 120
## For row 2: 7 * 8 * 9 = 504
multiply_result = np.multiply.reduce(arr, axis=1, dtype=float)

print("\nStep 4 Result (multiply.reduce with dtype=float):")
print(multiply_result)

Enregistrez et exécutez le script.

python ufunc_examples.py

Observez la sortie de l'étape 4.

... (previous output) ...

Step 4 Original Array:
[[1 2 3]
 [4 5 6]
 [7 8 9]]

Step 4 Result (multiply.reduce with dtype=float):
[  6. 120. 504.]

Remarquez les points qui suivent (.) dans le tableau de sortie [ 6. 120. 504.]. Cela indique que les éléments sont maintenant des nombres à virgule flottante, comme nous l'avons spécifié avec dtype=float.

Surcharge du Comportement des Ufuncs

Le système de ufuncs de NumPy est extensible. Vous pouvez créer vos propres objets de type tableau (array-like) qui définissent comment les ufuncs doivent opérer sur eux. C'est une fonctionnalité avancée, généralement réalisée en sous-classant ndarray de NumPy et en substituant des méthodes spéciales comme __add__ (pour l'opérateur +).

Créons une classe de tableau personnalisée simple qui affiche un message chaque fois qu'une addition est effectuée sur elle.

Ajoutez ce dernier bloc de code à ufunc_examples.py.

## --- Appended code for Step 5 ---

## Define a custom array class by subclassing np.ndarray
class MyArray(np.ndarray):
    def __add__(self, other):
        print("\nStep 5: Custom add method called!")
        ## Call the original implementation from the parent class
        return super().__add__(other)

## Create an instance of our custom class
## We must use .view() to cast the ndarray to our custom class
my_arr = np.array([10, 20, 30]).view(MyArray)

## Perform addition, which will trigger our custom method
override_result = my_arr + 5

print("Step 5 Result (Overridden Ufunc):")
print(override_result)

Enregistrez le fichier et exécutez-le une dernière fois.

python ufunc_examples.py

Vérifiez la sortie finale.

... (previous output) ...

Step 5: Custom add method called!
Step 5 Result (Overridden Ufunc):
[15 25 35]

Vous pouvez voir que notre message personnalisé a été imprimé avant le résultat de l'addition, confirmant que notre méthode __add__ a été appelée. Cela démontre la puissante flexibilité du système de ufuncs.

Résumé

Dans ce laboratoire, vous avez appris les bases des Fonctions Universelles (ufuncs) de NumPy. Nous avons commencé par les opérations arithmétiques élément par élément de base, qui constituent le fondement du calcul vectorisé. Vous avez ensuite exploré le broadcasting, une fonctionnalité clé qui permet à NumPy d'effectuer des opérations sur des tableaux de formes différentes. Nous avons également abordé comment utiliser les méthodes de ufunc comme .reduce() pour l'agrégation de données et comment contrôler le type de données de sortie avec l'argument dtype. Enfin, vous avez vu un exemple avancé de la manière de personnaliser le comportement des ufuncs en sous-classant np.ndarray. Avec ces compétences, vous êtes maintenant mieux équipé pour écrire du code numérique efficace, lisible et puissant avec NumPy.