Finora abbiamo esplorato le funzionalità di base e avanzate di NumPy in modo sistematico. Adesso, è il momento di vedere come queste capacità si traducano in soluzioni reali. Questa fase ti aprirà gli occhi su come NumPy sia uno strumento davvero irrinunciabile per chi si occupa di simulazioni, analisi di dati e problemi scientifici, spesso lavorando in tandem con altre librerie Python. Preparati a scoprire il lato pratico di NumPy, quello che lo rende un alleato prezioso nel tuo lavoro quotidiano con i dati.
👉 Vai al Tutorial Numpy Completo
Simulazioni (Es. Lancio di Dadi, Camminata Aleatoria)
NumPy è eccellente per le simulazioni grazie alla sua capacità di generare numeri casuali in modo efficiente e di eseguire operazioni vettorizzate.
Simulazione del Lancio di Dadi
Immagina di voler simulare il lancio di un dado a sei facce molte volte e analizzare i risultati.
import numpy as np
# Numero di lanci del dado
num_lanci = 10000
# Simulazione dei lanci di un dado a 6 facce (valori da 1 a 6)
# np.random.randint(low, high, size) genera interi casuali nell'intervallo [low, high)
risultati_dado = np.random.randint(1, 7, size=num_lanci)
print(f"Primi 10 risultati: {risultati_dado[:10]}")
print(f"Ultimi 10 risultati: {risultati_dado[-10:]}\n")
# Calcolo delle frequenze di ogni faccia
# np.bincount conta le occorrenze di valori non negativi in un array
frequenze = np.bincount(risultati_dado, minlength=7) # minlength=7 per includere indici da 0 a 6
# Le frequenze sono per indici 0, 1, 2, 3, 4, 5, 6. L'indice 0 non ci interessa per un dado.
# Per ottenere le frequenze delle facce 1-6, possiamo ignorare il primo elemento.
print("Frequenze delle facce:")
for faccia in range(1, 7):
print(f"Faccia {faccia}: {frequenze[faccia]} volte")
# Calcolo delle probabilità (frequenze relative)
probabilita = frequenze[1:] / num_lanci
print(f"\nProbabilità di ogni faccia: {probabilita}\n")
# Verifica che la somma delle probabilità sia 1 (o molto vicino a 1)
print(f"Somma delle probabilità: {np.sum(probabilita):.4f}\n")
Primi 10 risultati: [5 6 2 3 3 5 2 6 6 1]
Ultimi 10 risultati: [6 3 3 6 5 3 1 5 3 2]
Frequenze delle facce:
Faccia 1: 1657 volte
Faccia 2: 1709 volte
Faccia 3: 1638 volte
Faccia 4: 1678 volte
Faccia 5: 1600 volte
Faccia 6: 1718 volte
Probabilità di ogni faccia: [0.1657 0.1709 0.1638 0.1678 0.16 0.1718]
Somma delle probabilità: 1.0000
Spiegazione:
np.random.randint(1, 7, size=num_lanci)è la chiave qui. Genera un array dinum_lanciinteri casuali, dove ogni intero è compreso tra 1 (incluso) e 7 (escluso), simulando le facce di un dado.np.bincount()è una funzione utile per contare le occorrenze di ogni valore in un array di interi non negativi. L’argomentominlengthassicura che l’array delle frequenze abbia una dimensione minima, utile se alcune facce non dovessero comparire in un numero limitato di lanci.- Dividendo le frequenze per il numero totale di lanci, otteniamo le probabilità empiriche di ogni faccia.
Questo esercizio è interessante perché mostra come NumPy possa simulare rapidamente eventi casuali su larga scala. La sua peculiarità sta nell’uso efficiente di np.random.randint per generare un grande volume di dati in una singola operazione vettorizzata e di np.bincount per aggregare le frequenze in modo estremamente performante. Dal punto di vista applicativo, simulazioni di questo tipo sono fondamentali in ambiti come la statistica, la finanza (es. simulazioni Monte Carlo) o la gestione del rischio, dove è necessario esplorare un vasto spazio di risultati possibili per comprendere la probabilità di certi eventi.
Camminata Aleatoria (Random Walk)
Una camminata aleatoria è un modello matematico che descrive un percorso costituito da una successione di passi casuali.
È usata in fisica, finanza e biologia.
import numpy as np
import matplotlib.pyplot as plt
# Numero di passi nella camminata
num_passi = 1000
# Generiamo passi casuali: +1 o -1 con uguale probabilità
# np.random.choice([elementi], size, p=[probabilità])
passi = np.random.choice([-1, 1], size=num_passi)
# Calcoliamo la posizione ad ogni passo sommando cumulativamente i passi
# np.cumsum() calcola la somma cumulativa degli elementi
posizioni = np.cumsum(passi)
# Aggiungiamo la posizione iniziale (0) all'inizio
posizioni = np.insert(posizioni, 0, 0)
# Creiamo il grafico della camminata aleatoria
plt.figure(figsize=(10, 6))
plt.plot(posizioni)
plt.xlabel("Numero di Passi")
plt.ylabel("Posizione")
plt.title("Camminata Aleatoria 1D")
plt.grid(True)
plt.savefig("camminata_aleatoria.png")
# plt.show()
print(f"Posizione finale: {posizioni[-1]}")
print(f"Massima posizione raggiunta: {np.max(posizioni)}")
print(f"Minima posizione raggiunta: {np.min(posizioni)}\n")
Posizione finale: 0
Massima posizione raggiunta: 22
Minima posizione raggiunta: -17

Spiegazione:
np.random.choice([-1, 1], size=num_passi)genera una sequenza dinum_passidove ogni elemento è casualmente -1 o +1.np.cumsum(passi)è fondamentale: calcola la somma cumulativa. Sepassiè [1, -1, 1, 1],cumsumsarà [1, 0, 1, 2]. Questo ci dà la posizione dopo ogni passo.np.insert(posizioni, 0, 0)aggiunge la posizione iniziale 0 all’inizio dell’arrayposizioniper un grafico più completo.
La camminata aleatoria è un esempio affascinante di come un processo apparentemente semplice (passi casuali) possa generare pattern complessi. La peculiarità di questo esercizio risiede nell’uso di np.random.choice per definire i “passi” discreti e, soprattutto, di np.cumsum per tracciare la posizione nel tempo in modo cumulativo. Applicativamente, le camminate aleatorie modellano una miriade di fenomeni, dalla diffusione di molecole (moto browniano) ai prezzi delle azioni in finanza, fino ai movimenti di animali. Comprendere come simularle è un primo passo per analizzare sistemi dinamici con componenti casuali.
Analisi di Dati Semplici (Es. Temperature Medie)
NumPy è uno strumento eccellente per eseguire analisi statistiche di base su set di dati numerici.
Esempio: Analisi delle temperature giornaliere.
Supponiamo di avere un array di temperature registrate per una settimana e di voler calcolare alcune statistiche.
import numpy as np
temperature_settimanali = np.array([22.5, 23.1, 20.9, 24.0, 25.2, 21.8, 23.5])
print(f"Temperature settimanali: {temperature_settimanali}\n")
# Temperatura media
media_temp = np.mean(temperature_settimanali)
print(f"Temperatura media: {media_temp:.2f}°C")
# Temperatura massima e minima
max_temp = np.max(temperature_settimanali)
min_temp = np.min(temperature_settimanali)
print(f"Temperatura massima: {max_temp:.2f}°C")
print(f"Temperatura minima: {min_temp:.2f}°C")
# Deviazione standard (quanto variano le temperature)
dev_std_temp = np.std(temperature_settimanali)
print(f"Deviazione standard delle temperature: {dev_std_temp:.2f}°C")
# Differenza tra la temperatura massima e minima (range)
range_temp = np.ptp(temperature_settimanali) # Peak-to-peak range
print(f"Range delle temperature: {range_temp:.2f}°C\n")
# Trovare i giorni con temperature superiori a una certa soglia
soglia = 23.0
giorni_caldi = temperature_settimanali[temperature_settimanali > soglia]
print(f"Temperature superiori a {soglia}°C: {giorni_caldi}\n")
# Calcolare la media delle temperature solo dei giorni caldi
media_giorni_caldi = np.mean(giorni_caldi)
print(f"Media delle temperature dei giorni caldi: {media_giorni_caldi:.2f}°C\n")
Temperature settimanali: [22.5 23.1 20.9 24. 25.2 21.8 23.5]
Temperatura media: 23.00°C
Temperatura massima: 25.20°C
Temperatura minima: 20.90°C
Deviazione standard delle temperature: 1.32°C
Range delle temperature: 4.30°C
Temperature superiori a 23.0°C: [23.1 24. 25.2 23.5]
Media delle temperature dei giorni caldi: 23.95°C
Spiegazione:
- Abbiamo usato le funzioni di aggregazione (
mean,max,min,std) che abbiamo imparato nella Fase 4. np.ptp()(peak-to-peak) è una funzione comoda per calcolare la differenza tra il valore massimo e minimo di un array.- L’indicizzazione booleana (
temperature_settimanali > soglia) ci ha permesso di selezionare facilmente solo i dati che soddisfano una certa condizione, dimostrando la sua utilità nell’analisi dei dati.
Questo esempio dimostra la capacità di NumPy di eseguire analisi statistiche di base su array numerici con una sintassi pulita ed efficiente. La sua peculiarità risiede nell’immediatezza con cui si possono calcolare metriche descrittive come media, max, min, deviazione standard e range (np.ptp). L’indicizzazione booleana per filtrare i dati (es. temperature_settimanali > soglia) è un’altra caratteristica potente che semplifica enormemente la selezione di sottoinsiemi specifici di dati per ulteriori analisi. Dal punto di vista applicativo, questo è il pane quotidiano di data scientist e analisti che necessitano di estrarre rapidamente informazioni chiave da set di dati numerici, che siano temperature, vendite, misurazioni industriali o performance sportive.
Applicazioni in Fisica o Ingegneria (Es. Calcolo di Traiettorie)
NumPy è ampiamente utilizzato in campi scientifici per modellare fenomeni fisici e ingegneristici.
Esempio: Calcolo della traiettoria di un proiettile.
Consideriamo un proiettile lanciato con una velocità iniziale [math]v_0[/math] e un angolo [math]\theta[/math]. Le equazioni del moto (ignorando la resistenza dell’aria) sono:
[math]\displaystyle \begin{aligned}
x(t) &= v_0 \cos(\theta) t \\
y(t) &= v_0 \sin(\theta) t – \frac{1}{2} g t^2
\end{aligned}[/math]
dove [math]g[/math] è l’accelerazione di gravità (circa [math]9.81 \text{ m/s}^2[/math]).
import numpy as np
import matplotlib.pyplot as plt
# Parametri iniziali
v0 = 50 # Velocità iniziale (m/s)
angolo_gradi = 45 # Angolo di lancio (gradi)
g = 9.81 # Accelerazione di gravità (m/s^2)
# Converti l'angolo da gradi a radianti
angolo_rad = np.deg2rad(angolo_gradi)
# Calcola il tempo di volo totale (quando y torna a 0)
# y(t) = 0 => v0*sin(theta)*t - 0.5*g*t^2 = 0
# t * (v0*sin(theta) - 0.5*g*t) = 0
# t = 0 (inizio) o t = (2 * v0 * sin(theta)) / g
t_volo = (2 * v0 * np.sin(angolo_rad)) / g
# Genera un array di tempi da 0 al tempo di volo
tempi = np.linspace(0, t_volo, 100) # 100 punti temporali
# Calcola le posizioni x e y ad ogni tempo
x_pos = v0 * np.cos(angolo_rad) * tempi
y_pos = v0 * np.sin(angolo_rad) * tempi - 0.5 * g * tempi**2
# Trova il punto di impatto (dove y è circa 0 e x è massima)
# A causa di errori di floating point, y potrebbe non essere esattamente 0
# Troviamo l'indice del punto in cui y è più vicino a 0 alla fine della traiettoria
indice_impatto = np.argmin(np.abs(y_pos[y_pos >= 0])) # Trova l'indice dove y è quasi 0 (e non negativo)
portata = x_pos[indice_impatto]
# Trova l'altezza massima
altezza_max = np.max(y_pos)
print(f"Tempo di volo: {t_volo:.2f} s")
print(f"Portata (distanza orizzontale): {portata:.2f} m")
print(f"Altezza massima: {altezza_max:.2f} m\n")
# Creiamo il grafico della traiettoria
plt.figure(figsize=(10, 6))
plt.plot(x_pos, y_pos)
plt.xlabel("Distanza Orizzontale (m)")
plt.ylabel("Altezza (m)")
plt.title(f"Traiettoria del Proiettile (v0={v0} m/s, angolo={angolo_gradi}°)")
plt.grid(True)
plt.axhline(0, color='black', linestyle='--', linewidth=0.8) # Linea dell'asse x
plt.ylim(bottom=0) # Assicurati che l'asse y parta da 0
plt.savefig("traiettoria_proiettile.png")
plt.show()
Tempo di volo: 7.21 s
Portata (distanza orizzontale): 0.00 m
Altezza massima: 63.70 m

Spiegazione:
np.deg2rad()converte l’angolo da gradi a radianti, poiché le funzioni trigonometriche di NumPy (e Python) lavorano con radianti.- Abbiamo usato
np.linspace()per creare un array di tempi, e poi le operazioni vettorizzate di NumPy per calcolare le posizionix_posey_posper tutti i tempi contemporaneamente. np.argmin(np.abs(y_pos[y_pos >= 0]))è un esempio di come combinare indicizzazione booleana e funzioni di aggregazione per trovare un punto specifico (l’impatto).- Matplotlib è stato usato per visualizzare la traiettoria, rendendo il fenomeno fisico immediatamente comprensibile.
Questo è un classico esempio di come NumPy renda accessibile la modellazione di fenomeni fisici complessi. La peculiarità qui è l’uso di operazioni vettorizzate per calcolare simultaneamente la posizione di un proiettile in ogni istante di tempo lungo la sua traiettoria, evitando cicli espliciti. np.linspace è fondamentale per creare un campionamento uniforme del tempo, e la combinazione di funzioni matematiche di NumPy (np.sin, np.cos, np.deg2rad) con operazioni sugli array rende il codice conciso e leggibile. Applicativamente, questo approccio è estensibile a simulazioni di sistemi dinamici in ingegneria, astrofisica, robotica, dove la precisione e l’efficienza nel calcolo di molteplici punti di una curva o traiettoria sono cruciali
Esempi di Integrazione con Altre Librerie (Pandas, Scikit-learn)
NumPy è la base per l’intero ecosistema scientifico di Python. Molte altre librerie accettano array NumPy come input o restituiscono array NumPy come output.
Integrazione con Pandas
Pandas è una libreria per l’analisi e la manipolazione di dati, che introduce le strutture dati Series e DataFrame. Internamente, Pandas si basa su NumPy per l’archiviazione e le operazioni efficienti.
import numpy as np
import pandas as pd
# Creiamo un array NumPy
dati_numpy = np.array([
[10, 150, 25],
[12, 160, 28],
[11, 155, 26],
[13, 165, 29]])
# Convertiamo l'array NumPy in un DataFrame Pandas
df = pd.DataFrame(dati_numpy, columns=["Età", "Altezza (cm)", "Peso (kg)"])
print(f"DataFrame Pandas:\n{df}\n")
# Possiamo estrarre colonne come Series Pandas, che internamente sono array NumPy
altezza_series = df["Altezza (cm)"]
print(f"Serie Altezza:\n{altezza_series}\n")
print(f"Tipo della serie: {type(altezza_series)}")
print(f"Tipo dei valori sottostanti: {type(altezza_series.values)}\n")
# Possiamo eseguire operazioni NumPy direttamente sui valori sottostanti
media_altezza_numpy = np.mean(altezza_series.values)
print(f"Media altezza (usando np.mean su valori NumPy): {media_altezza_numpy:.2f} cm\n")
# E viceversa, possiamo convertire Series/DataFrame in array NumPy
df_to_numpy = df.to_numpy()
print(f"DataFrame convertito in NumPy array:\n{df_to_numpy}\n")
DataFrame Pandas: Età Altezza (cm) Peso (kg) 0 10 150 25 1 12 160 28 2 11 155 26 3 13 165 29 Serie Altezza: 0 150 1 160 2 155 3 165 Name: Altezza (cm), dtype: int64 Tipo della serie: <class 'pandas.core.series.Series'> Tipo dei valori sottostanti: <class 'numpy.ndarray'> Media altezza (usando np.mean su valori NumPy): 157.50 cm DataFrame convertito in NumPy array: [[ 10 150 25] [ 12 160 28] [ 11 155 26] [ 13 165 29]]
Spiegazione:
pd.DataFrame(dati_numpy, ...)crea un DataFrame direttamente da un array NumPy 2D.- L’attributo
.valuesdi una Series o DataFrame restituisce l’array NumPy sottostante, permettendoti di usare tutte le funzioni NumPy direttamente su di esso. df.to_numpy()converte un DataFrame Pandas in un array NumPy.
Questo esempio sottolinea il ruolo di NumPy come “lingua franca” nel mondo del data science in Python. La sua peculiarità risiede nel fatto che Pandas, pur offrendo strutture dati più complesse (DataFrame, Series), si basa internamente su array NumPy per l’efficienza computazionale. L’interoperabilità è quasi trasparente: si può passare facilmente da NumPy a Pandas e viceversa, e le operazioni NumPy possono essere applicate direttamente sui valori sottostanti di oggetti Pandas. Applicativamente, questo è vitale per chiunque lavori con dati tabulari: si usano le potenti funzionalità di manipolazione e pulizia di Pandas, ma si ha la certezza che le operazioni numeriche più intensive saranno gestite efficientemente da NumPy, beneficiando di tutta la sua ottimizzazione.
Integrazione con Scikit-learn (Machine Learning)
Scikit-learn è la libreria più popolare per il machine learning in Python. Quasi tutti i suoi algoritmi si aspettano i dati di input come array NumPy.
Esempio: Regressione Lineare Semplice.
import numpy as np
from sklearn.linear_model import LinearRegression
import matplotlib.pyplot as plt
# Generiamo dati di esempio (relazione lineare con rumore)
x_ml = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).reshape(-1, 1) # Feature (deve essere 2D per sklearn)
y_ml = np.array([2, 4, 5, 4, 6, 7, 9, 10, 11, 12]) # Target
# Creiamo un modello di regressione lineare
model = LinearRegression()
# Addestriamo il modello sui nostri dati (NumPy arrays)
model.fit(x_ml, y_ml)
# Facciamo previsioni
previsioni = model.predict(x_ml)
print(f"Coefficiente (pendenza): {model.coef_[0]:.2f}")
print(f"Intercetta: {model.intercept_:.2f}\n")
# Visualizziamo i dati e la linea di regressione
plt.figure(figsize=(8, 6))
plt.scatter(x_ml, y_ml, color='blue', label='Dati Reali')
plt.plot(x_ml, previsioni, color='red', label='Linea di Regressione')
plt.xlabel("X")
plt.ylabel("Y")
plt.title("Regressione Lineare con Scikit-learn e NumPy")
plt.legend()
plt.grid(True)
plt.savefig("regressione_lineare.png")
plt.show()
Coefficiente (pendenza): 1.09
Intercetta: 1.00

Spiegazione:
- I dati
x_mley_mlsono array NumPy. x_ml.reshape(-1, 1)è importante: Scikit-learn si aspetta che le feature (X) siano un array 2D, anche se c’è una sola feature.-1indica a NumPy di calcolare automaticamente la dimensione della riga, mentre1forza una singola colonna.- Il metodo
fit()del modello accetta array NumPy per l’addestramento. - Il metodo
predict()restituisce previsioni come array NumPy.
Questo esempio è cruciale per chiunque intenda intraprendere il percorso del machine learning in Python. La sua peculiarità sta nel dimostrare che Scikit-learn, la libreria di ML più diffusa, si aspetta e restituisce dati come array NumPy. Questo rafforza l’idea che una solida comprensione di NumPy è una precondizione per utilizzare efficacemente queste librerie di alto livello. L’esempio di regressione lineare mostra come la preparazione dei dati (es. reshape(-1, 1)) sia un passaggio comune e necessario con NumPy per adattarsi ai requisiti degli algoritmi. Applicativamente, ogni modello di machine learning, dalla classificazione alla regressione, dall’apprendimento non supervisionato all’elaborazione del linguaggio naturale (tramite embeddings), fa affidamento su array NumPy per l’input e l’output dei dati, rendendo NumPy la spina dorsale di quasi ogni pipeline di ML.
Hai visto NumPy in azione in vari contesti pratici, dalle simulazioni all’analisi di dati e all’integrazione con altre librerie. Spero che questi esempi ti abbiano dato una chiara idea della versatilità e della potenza di NumPy.





