Python e NumPy: broadcasting e operazioni vettoriali in pratica

by theArchitect
SHARE
Python e NumPy: broadcasting e operazioni vettoriali in pratica
© Guida-HTML5.it

Introduzione

Quando si inizia a usare NumPy, uno dei salti di qualità più importanti non è semplicemente “creare array”, ma imparare a sfruttare il broadcasting. Questo meccanismo permette di eseguire operazioni tra array di forme diverse in modo elegante, veloce e leggibile, senza dover scrivere cicli for manuali.

Il broadcasting è uno dei motivi per cui NumPy è così potente nella computazione scientifica, nell’analisi dati e nel machine learning. Ti consente, ad esempio, di sommare un vettore a ogni riga di una matrice, normalizzare colonne, applicare offset, convertire unità di misura o calcolare distanze in modo compatto.

In questo tutorial vedremo un sotto-argomento utile e molto pratico: come usare il broadcasting per semplificare operazioni vettoriali su array di forme diverse. L’obiettivo è capire non solo come funziona, ma anche quando conviene usarlo e quali errori evitare.

Codice completo

import numpy as np

# 1) Creiamo una matrice di dati: 4 studenti, 3 voti
voti = np.array([
    [28, 30, 27],
    [24, 26, 29],
    [18, 22, 25],
    [30, 29, 30]
])

# 2) Creiamo un vettore di bonus da aggiungere a ogni materia
bonus_materia = np.array([1, 0, 2])

# 3) Usiamo il broadcasting: il vettore viene applicato a ogni riga
voti_corretto = voti + bonus_materia

print("Voti originali:")
print(voti)
print("nBonus per materia:")
print(bonus_materia)
print("nVoti corretti con broadcasting:")
print(voti_corretto)

# 4) Calcoliamo la media per ogni studente
media_studenti = voti_corretto.mean(axis=1)

print("nMedia finale di ogni studente:")
print(media_studenti)

# 5) Normalizzazione semplice: sottraiamo la media di ogni colonna
medie_colonne = voti.mean(axis=0)
voti_centrati = voti - medie_colonne

print("nMedie delle colonne:")
print(medie_colonne)
print("nMatrice centrata rispetto alle medie di colonna:")
print(voti_centrati)

# 6) Esempio pratico con conversione di unità
# Dati in centimetri per 3 misure
lunghezze_cm = np.array([12.5, 8.0, 15.2])

# Convertiamo in metri dividendo per 100
lunghezze_m = lunghezze_cm / 100

print("nLunghezze in cm:")
print(lunghezze_cm)
print("Lunghezze in m:")
print(lunghezze_m)

# 7) Esempio con una matrice di coordinate e uno spostamento
coordinate = np.array([
    [10, 20],
    [15, 25],
    [30, 40]
])

spostamento = np.array([5, -3])

coordinate_nuove = coordinate + spostamento

print("nCoordinate originali:")
print(coordinate)
print("nSpostamento applicato a tutte le coordinate:")
print(spostamento)
print("nCoordinate aggiornate:")
print(coordinate_nuove)

# 8) Controllo delle forme per capire il broadcasting
print("nForma di voti:", voti.shape)
print("Forma di bonus_materia:", bonus_materia.shape)
print("Forma di coordinate:", coordinate.shape)
print("Forma di spostamento:", spostamento.shape)

Spiegazione

Il broadcasting è una regola che NumPy usa per rendere compatibili array con forme diverse durante un’operazione element-wise, come somma, sottrazione, moltiplicazione o divisione. In pratica, NumPy “estende mentalmente” l’array più piccolo lungo le dimensioni compatibili, senza creare copie inutili in memoria.

1. Sommare un vettore a una matrice

Nel primo esempio abbiamo una matrice voti di forma (4, 3) e un vettore bonus_materia di forma (3,). NumPy interpreta il vettore come se fosse una riga da applicare a ciascuna delle 4 righe della matrice.

Il risultato è una nuova matrice in cui ogni colonna ha ricevuto il proprio bonus. Questa tecnica è utilissima quando vuoi correggere o trasformare dati tabellari in modo uniforme.

2. Operazioni per colonna con axis

Dopo aver applicato il bonus, calcoliamo la media per ogni studente usando axis=1. Qui non stiamo facendo broadcasting, ma stiamo sfruttando un’altra idea fondamentale di NumPy: le operazioni vettoriali su assi specifici. Il risultato è un array monodimensionale con una media per riga.

Invece, quando facciamo voti - medie_colonne, NumPy sottrae a ogni colonna il suo valore medio. Questo è un esempio classico di centratura dei dati, utile in statistica e preprocessing.

3. Conversione di unità

L’operazione lunghezze_cm / 100 è banalmente vettoriale: NumPy applica la divisione a ogni elemento dell’array. Anche se questo esempio non richiede broadcasting tra forme diverse, mostra bene il vantaggio di lavorare con array invece che con liste Python.

4. Applicare uno spostamento a coordinate 2D

Nel caso delle coordinate, abbiamo una matrice di punti di forma (3, 2) e un vettore di spostamento di forma (2,). NumPy applica lo spostamento a ogni punto: il primo valore viene sommato alla coordinata x, il secondo alla coordinata y.

Questo è molto comune in grafica, simulazioni fisiche, robotica e analisi geometrica. Con un solo comando puoi aggiornare centinaia o migliaia di punti.

5. Come ragiona NumPy sul broadcasting

Per capire il meccanismo, puoi pensare a queste regole semplificate:

  • Le dimensioni vengono confrontate da destra verso sinistra.
  • Due dimensioni sono compatibili se sono uguali oppure se una delle due vale 1.
  • Se una dimensione è 1, NumPy la “espande” virtualmente.

Per esempio, un array di forma (4, 3) e uno di forma (3,) sono compatibili perché il secondo viene interpretato come (1, 3), quindi replicato sulle 4 righe.

6. Errori comuni

Non tutte le forme sono compatibili. Se provi a sommare array con dimensioni incompatibili, NumPy genererà un errore. Questo è un bene: evita risultati ambigui o silenziosamente sbagliati.

Ad esempio, un array di forma (4, 3) non può essere combinato con uno di forma (2,) per un’operazione tra colonne, perché le dimensioni non si allineano correttamente.

Best practice

  • Controlla sempre le forme con .shape prima di fare operazioni tra array. Ti aiuta a capire subito se il broadcasting è possibile.
  • Preferisci il broadcasting ai cicli Python quando l’operazione è applicabile a tutti gli elementi. Il codice sarà più breve e molto più veloce.
  • Usa nomi chiari per gli array, soprattutto quando lavori con matrici e vettori di dimensioni diverse. Ad esempio, medie_colonne è più esplicito di m.
  • Evita di forzare forme strane se non necessario. A volte basta un array 1D ben costruito; altre volte può servire reshape, ma va usato con consapevolezza.
  • Verifica il significato matematico del broadcasting. Il fatto che un’operazione funzioni tecnicamente non significa sempre che sia corretta dal punto di vista del dominio applicativo.
  • Documenta le trasformazioni dei dati nei progetti reali, soprattutto se il broadcasting viene usato in pipeline di preprocessing o calcolo scientifico.

Riepilogo

Il broadcasting è una delle funzionalità più utili di NumPy perché permette di combinare array con forme diverse in modo naturale e performante. In questo tutorial hai visto come:

  • aggiungere un vettore a ogni riga di una matrice;
  • centrare i dati sottraendo le medie di colonna;
  • applicare uno spostamento a un insieme di coordinate;
  • capire le regole base che rendono possibile il broadcasting;
  • evitare gli errori più comuni legati alle forme incompatibili.

Se stai iniziando con NumPy, padroneggiare il broadcasting ti farà scrivere codice più pulito, più veloce e più vicino al linguaggio matematico dei problemi che vuoi risolvere.

Approfondisci con risorse ufficiali

SHARE