Le Ufunc di NumPy sono uno degli strumenti più utili per eseguire operazioni matematiche sugli array in modo rapido, leggibile e molto più comodo rispetto ai classici cicli Python. Se stai iniziando a usare questa libreria, capire come funziona l’aritmetica Ufunc in NumPy è un passaggio fondamentale per lavorare bene con i dati numerici.
In questa guida vedremo come usare le operazioni principali, cioè addizione, sottrazione, moltiplicazione e divisione, con esempi semplici e subito applicabili. L’obiettivo è aiutarti a comprendere non solo la sintassi, ma anche il comportamento concreto delle Ufunc quando agiscono su array di diverse forme e dimensioni.
Come funzionano le Ufunc di NumPy
Il termine Ufunc significa “universal function”. In pratica, si tratta di funzioni pensate per applicare una stessa operazione a tutti gli elementi di uno o più array. Questo approccio rende il codice più pulito, più veloce e anche più naturale da leggere.
In NumPy, molte operazioni aritmetiche possono essere scritte sia con gli operatori classici come +, –, * e /, sia con funzioni esplicite come np.add(), np.subtract(), np.multiply() e np.divide(). Le due strade portano spesso allo stesso risultato, ma conoscere le Ufunc ti aiuta a capire meglio la logica interna della libreria.
Per iniziare, importiamo NumPy e creiamo due array numerici:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
Da questo punto in poi, ogni operazione verrà eseguita elemento per elemento. Significa che il primo valore di a verrà combinato con il primo valore di b, il secondo con il secondo, e così via.
Somma tra array con le Ufunc di NumPy
L’addizione è uno degli esempi più immediati per capire il funzionamento delle Ufunc. Se hai due array della stessa lunghezza, NumPy somma ogni coppia di elementi corrispondenti.
Puoi usare la funzione dedicata oppure l’operatore classico:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = np.add(a, b)
print(risultato)
L’output sarà un array con i valori sommati:
[11 22 33]
Lo stesso risultato si può ottenere anche così:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = a + b
print(risultato)
Dal punto di vista pratico, np.add() diventa particolarmente interessante quando vuoi scrivere codice più esplicito o concatenare operazioni in contesti un po’ più strutturati. Per chi è alle prime armi, è utile sapere che entrambe le sintassi sono corrette e molto comuni.
Un altro caso frequente è l’addizione tra un array e un numero singolo. NumPy applica il valore a tutti gli elementi:
import numpy as np
a = np.array([10, 20, 30])
risultato = np.add(a, 5)
print(risultato)
Qui entra in gioco un concetto molto importante di NumPy chiamato broadcasting. In termini semplici, il numero 5 viene esteso virtualmente su tutto l’array, senza che tu debba scrivere cicli o creare strutture aggiuntive.
Differenza tra array: sottrazione con NumPy Ufunc
La sottrazione segue la stessa logica dell’addizione. Ogni elemento del primo array viene diminuito del valore corrispondente nel secondo array. Anche in questo caso puoi scegliere tra funzione esplicita e operatore tradizionale.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = np.subtract(a, b)
print(risultato)
Il risultato sarà:
[ 9 18 27]
Se preferisci una forma più sintetica, puoi scrivere:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = a - b
print(risultato)
Vale la pena soffermarsi su un dettaglio concreto: nell’aritmetica con le Ufunc, l’ordine degli operandi conta. Sottrarre b da a non è la stessa cosa che sottrarre a da b.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
print(np.subtract(a, b))
print(np.subtract(b, a))
Questa osservazione sembra banale, ma in molti casi reali evita errori di logica, soprattutto quando lavori con differenze tra valori misurati, serie temporali o risultati di confronti numerici.
Prodotto elemento per elemento con NumPy
La moltiplicazione tra array in NumPy, quando usi le Ufunc o l’operatore *, viene eseguita elemento per elemento. Questo è un punto da ricordare bene, perché chi arriva da altri contesti può pensare a una moltiplicazione matriciale, che invece segue regole diverse.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = np.multiply(a, b)
print(risultato)
L’output sarà:
[10 40 90]
In alternativa:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = a * b
print(risultato)
Questa operazione è molto usata nell’elaborazione numerica, ad esempio per applicare coefficienti, pesi o fattori di scala a una sequenza di valori. È una delle forme più immediate per trattare dati in modo vettoriale, senza appesantire il codice.
Se invece vuoi moltiplicare tutti gli elementi di un array per uno stesso numero, NumPy lo gestisce in maniera altrettanto lineare:
import numpy as np
a = np.array([10, 20, 30])
risultato = np.multiply(a, 2)
print(risultato)
In questo caso il risultato sarà un array con tutti i valori raddoppiati. È una soluzione semplice ma molto potente, soprattutto quando devi trasformare grandi quantità di dati in poche righe di codice.
Divisione tra array con le universal function di NumPy
La divisione in NumPy si esegue con np.divide() oppure con l’operatore /. Anche qui il comportamento standard è elemento per elemento.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = np.divide(a, b)
print(risultato)
L’output sarà:
[10. 10. 10.]
Nota un aspetto importante: il risultato della divisione è spesso espresso in formato float, anche quando i numeri iniziali sono interi. È un comportamento normale e molto utile, perché evita la perdita della parte decimale.
Puoi ottenere lo stesso risultato anche in forma abbreviata:
import numpy as np
a = np.array([10, 20, 30])
b = np.array([1, 2, 3])
risultato = a / b
print(risultato)
Quando lavori con la divisione, è bene fare attenzione ai casi in cui il divisore contiene uno zero. NumPy, in queste situazioni, non sempre blocca l’esecuzione con un errore immediato come farebbe Python puro; può invece restituire valori speciali come inf o nan, accompagnati da un avviso.
import numpy as np
a = np.array([10, 20, 30])
b = np.array([2, 0, 5])
risultato = np.divide(a, b)
print(risultato)
Per chi inizia, questo dettaglio è prezioso: controllare i dati prima della divisione aiuta a evitare risultati inattesi e rende il codice più affidabile.