La libreria fondamentale per il calcolo scientifico in Python
Hai mai provato a sommare 1000 numeri con un calcolatore normale? Ci vorrebbero ore! E se ti dicessi che con NumPy puoi fare operazioni su milioni di numeri in pochi millisecondi?
In questo modulo scoprirai NumPy, la libreria che trasforma Python in una macchina da calcolo super-veloce. È la base di tutto il Machine Learning e la Data Science!
Liste Python normali sono come fare la spesa con un carrello piccolo: puoi mettere qualsiasi cosa (mele, libri, scarpe), ma è lento e disorganizzato.
Array NumPy sono come i pallet di un supermercato: tutti gli articoli sono dello stesso tipo, perfettamente organizzati, e puoi muovere 1000 scatole tutte insieme con un solo carrello elevatore! ⚡
NumPy (Numerical Python) è una libreria, cioè un "pacchetto aggiuntivo" che puoi installare in Python per ottenere nuove funzionalità. In particolare, NumPy ti dà un nuovo tipo di dato chiamato array, pensato apposta per lavorare con i numeri in modo velocissimo.
Le operazioni su array NumPy sono fino a 100 volte più veloci delle liste Python normali
Puoi eseguire operazioni su migliaia di elementi contemporaneamente, senza scrivere loop!
Pandas, TensorFlow, Scikit-Learn... tutte le librerie AI usano NumPy come fondamenta
💡 Perché è così veloce?
NumPy è scritto in C e Fortran (linguaggi super-ottimizzati), non in Python puro. È come avere un motore di Formula 1 invece di una bicicletta! 🏎️
✅ Se hai Anaconda: Niente da fare!
NumPy è già installato con Anaconda. Sei pronto a partire! 🎉
Apri il terminale e digita:
pip install numpyPrima di usare NumPy, devi importarlo. Importare significa dire a Python: "Carica questa libreria, ne ho bisogno!"
import numpy as np
print("NumPy versione:", np.__version__)
print("✅ NumPy è pronto all'uso!")import numpy as npimport numpy → dice a Python: "carica la libreria NumPy nel mio programma".
as np → le assegna un soprannome breve. Invece di scrivere numpy.qualcosa() ogni volta, scriverai np.qualcosa(). Meno lettere, stesso risultato!
Tutti i programmatori del mondo usano il soprannome np per NumPy. È una convenzione universale.
Da questo momento, ogni volta che vedi np. nel codice, sappi che stiamo usando una funzione di NumPy.
Per calcolare la media di alcuni voti con una lista normale, devi scrivere un ciclo for e fare i conti a mano:
voti = [7, 8, 6, 9, 7.5, 8.5]
somma = 0
for voto in voti:
somma += voto
media = somma / len(voti)
print(f"Media: {media:.2f}") # 7.67Con NumPy, crei un array e poi usi la funzione .mean() che calcola la media al posto tuo, senza loop:
import numpy as np
voti_np = np.array([7, 8, 6, 9, 7.5, 8.5])
media = voti_np.mean()
print(f"Media: {media:.2f}") # 7.67np.array([7, 8, 6, 9, 7.5, 8.5])np → è NumPy (il soprannome che gli abbiamo dato).
.array() → è una funzione di NumPy che crea un nuovo array.
[7, 8, 6, 9, 7.5, 8.5] → è la lista di numeri che vuoi mettere dentro l'array.
In pratica stai dicendo: "NumPy, prendi questi numeri e trasformali in un array super-veloce!"
voti_np.mean()Quando hai un array NumPy, puoi usare il punto . seguito dal nome di una funzione per fare calcoli. Queste funzioni "appartengono" all'array e sanno lavorare sui suoi dati.
voti_np.mean() → calcola la media di tutti i numeri nell'array.
voti_np.min() → trova il valore più piccolo.
voti_np.max() → trova il valore più grande.
voti_np.sum() → calcola la somma di tutti i numeri.
voti_np.std() → calcola la deviazione standard (quanto i valori sono "sparsi").
È come se l'array fosse un oggetto "intelligente" che sa già fare i calcoli su sé stesso!
⚠️ Regola d'Oro di NumPy:
Gli array NumPy devono contenere tutti elementi dello stesso tipo (tutti numeri interi, oppure tutti numeri con la virgola, ecc.). Questo è il segreto della loro velocità!
Le liste Python possono avere tipi misti (numeri, stringhe, booleani...) ma sono più lente.
Il modo più semplice: prendi una lista e la trasformi in array con np.array().
import numpy as np
temperature = [22, 25, 18, 30, 15, 28]
temp_array = np.array(temperature)
print("Temperature:", temp_array)
print("Tipo elementi:", temp_array.dtype).dtypedtype sta per "data type" (tipo di dato). Ti dice che tipo di numeri ci sono dentro l'array.
Per esempio: int64 significa "numeri interi", float64 significa "numeri con la virgola".
A differenza di .mean(), qui non ci sono le parentesi perché dtype non è una funzione da eseguire, ma una proprietà (un'informazione) dell'array.
np.zeros()Crea un array pieno di zeri. Utile quando sai la dimensione ma lo riempirai dopo.
zeri = np.zeros(5)
print("5 zeri:", zeri) # [0. 0. 0. 0. 0.]
# Per una tabella (2D): servono le doppie parentesi
tabella_zeri = np.zeros((3, 4)) # 3 righe, 4 colonne
print("Tabella 3x4 di zeri:")
print(tabella_zeri)np.zeros((3, 4)) ha le doppie parentesi?Le parentesi esterne sono quelle normali della funzione zeros().
Le parentesi interne (3, 4) formano una tupla, cioè una coppia di numeri che indica la forma: 3 righe e 4 colonne.
Se vuoi un semplice array di 5 elementi, basta np.zeros(5) (una sola parentesi).
np.ones()Come zeros() ma riempie tutto con il numero 1. Utile per creare array con un valore a scelta:
uni = np.ones(5)
print("5 uni:", uni) # [1. 1. 1. 1. 1.]
# Trucco: moltiplica per avere un array con il valore che vuoi
array_di_10 = np.ones(5) * 10
print("5 dieci:", array_di_10) # [10. 10. 10. 10. 10.]arange() e linspace()# arange(inizio, fine, passo) → numeri a salti regolari
# "Parti da 0, vai fino a 10 (escluso), a salti di 2"
numeri = np.arange(0, 10, 2)
print("arange(0, 10, 2):", numeri) # [0 2 4 6 8]
# linspace(inizio, fine, quanti) → N punti equidistanti
# "Dammi 5 punti distribuiti uniformemente tra 0 e 1"
punti = np.linspace(0, 1, 5)
print("linspace(0, 1, 5):", punti) # [0. 0.25 0.5 0.75 1. ]Con arange decidi il passo (ogni quanto saltare) e NumPy calcola quanti numeri escono.
Con linspace decidi quanti numeri vuoi e NumPy calcola il passo automaticamente.
# 5 numeri casuali decimali tra 0 e 1
casuali = np.random.random(5)
print("Casuali:", casuali)
# 10 numeri interi casuali tra 1 e 6 (come un dado)
dadi = np.random.randint(1, 7, size=10)
print("10 lanci di dado:", dadi)
# Distribuzione normale (campana di Gauss)
# loc = media desiderata, scale = deviazione standard, size = quanti
altezze = np.random.normal(loc=170, scale=10, size=5)
print("5 altezze casuali (media ~170cm):", altezze)np.random.randint(1, 7, size=10)np.random → il sotto-modulo di NumPy dedicato ai numeri casuali.
.randint(1, 7, ...) → genera numeri interi casuali. Il primo numero (1) è il minimo, il secondo (7) è il massimo escluso. Quindi i valori possibili sono: 1, 2, 3, 4, 5, 6.
size=10 → quanti numeri casuali generare.
np.random.normal(loc=170, scale=10, size=5)Questa funzione genera numeri casuali che seguono la distribuzione normale (la famosa "campana di Gauss"). I numeri generati saranno concentrati attorno alla media, con pochi valori molto lontani.
loc=170 → la media (il centro della campana). I numeri generati saranno "attorno" a 170.
scale=10 → la deviazione standard (quanto i numeri si allontanano dalla media). Più è grande, più i numeri sono "sparsi".
size=5 → quanti numeri generare.
Ecco la vera magia di NumPy: puoi fare operazioni matematiche su tutti gli elementi di un array contemporaneamente, senza scrivere nessun ciclo for!
Quando usi +, -, * o / tra due array della stessa lunghezza, NumPy applica l'operazione posizione per posizione:
import numpy as np
a = np.array([1, 2, 3, 4, 5])
b = np.array([10, 20, 30, 40, 50])
print("a + b =", a + b) # [11 22 33 44 55]
print("a * b =", a * b) # [10 40 90 160 250]
print("a ** 2 =", a ** 2) # [1 4 9 16 25]a + b, passo per passo:
Posizione 0: 1 + 10 = 11
Posizione 1: 2 + 20 = 22
Posizione 2: 3 + 30 = 33
Posizione 3: 4 + 40 = 44
Posizione 4: 5 + 50 = 55
Risultato finale: [11, 22, 33, 44, 55]Puoi anche usare un singolo numero con un intero array. NumPy applica quel numero a ogni elemento automaticamente. Questo meccanismo si chiama broadcasting:
prezzi = np.array([10, 20, 30, 40, 50])
# Aumento del 20% su TUTTI i prezzi
nuovi_prezzi = prezzi * 1.2
print("Prezzi +20%:", nuovi_prezzi) # [12. 24. 36. 48. 60.]
# Sconto di 5€ su TUTTI
scontati = prezzi - 5
print("Prezzi -5€:", scontati) # [5 15 25 35 45]prezzi * 1.2:
NumPy "espande" il numero 1.2 e lo applica a ogni elemento:
10 * 1.2 = 12.0
20 * 1.2 = 24.0
30 * 1.2 = 36.0
40 * 1.2 = 48.0
50 * 1.2 = 60.0
Risultato: [12.0, 24.0, 36.0, 48.0, 60.0]scritto = np.array([7, 8, 6, 9, 7.5])
orale = np.array([8, 7.5, 7, 8.5, 8])
# Media ponderata: scritto vale 60%, orale vale 40%
voto_finale = scritto * 0.6 + orale * 0.4
print("Voti finali:", voto_finale)scritto * 0.6 + orale * 0.4:
Prima: scritto * 0.6
7*0.6=4.2 8*0.6=4.8 6*0.6=3.6 9*0.6=5.4 7.5*0.6=4.5
Poi: orale * 0.4
8*0.4=3.2 7.5*0.4=3.0 7*0.4=2.8 8.5*0.4=3.4 8*0.4=3.2
Infine: somma posizione per posizione
4.2+3.2=7.4 4.8+3.0=7.8 3.6+2.8=6.4 5.4+3.4=8.8 4.5+3.2=7.7
Risultato: [7.4, 7.8, 6.4, 8.8, 7.7]Fino ad ora abbiamo usato array 1D (una riga di numeri). Ma NumPy può anche gestire tabelle con righe e colonne, proprio come un foglio Excel. Queste tabelle si chiamano array 2D o matrici.
Per creare un array 2D, passi a np.array() una lista di liste. Ogni lista interna diventa una riga:
import numpy as np
# 3 studenti, 4 materie ciascuno
voti_classe = np.array([
[7, 8, 6, 9], # Riga 0 = Studente 0
[8, 7, 7.5, 8.5], # Riga 1 = Studente 1
[6, 6.5, 7, 7] # Riga 2 = Studente 2
])
print("Voti:")
print(voti_classe)
print("Forma:", voti_classe.shape) # (3, 4) = 3 righe, 4 colonne
print("Totale elementi:", voti_classe.size) # 12
print("Numero dimensioni:", voti_classe.ndim) # 2.shape, .size, .ndimSono tre proprietà che ti danno informazioni sulla struttura dell'array:
.shape → la forma dell'array. (3, 4) significa 3 righe e 4 colonne.
.size → il numero totale di elementi (3 × 4 = 12).
.ndim → il numero di dimensioni. Un array 1D (una riga) ha ndim=1, un array 2D (tabella) ha ndim=2.
Immagina una tabella: le righe sono studenti, le colonne sono materie
Per accedere a un valore devi dire a NumPy quale riga e quale colonna vuoi, usando la sintassi matrice[riga, colonna]. Ricorda: si conta sempre da 0!
# Un singolo valore: [riga, colonna]
print(voti_classe[0, 2]) # Riga 0, Colonna 2 → 6
# Un'intera riga: basta l'indice della riga
print(voti_classe[1]) # Tutta la Riga 1 → [8, 7, 7.5, 8.5]
# Un'intera colonna: usa : per dire "tutte le righe"
print(voti_classe[:, 0]) # Tutte le righe, Colonna 0 → [7, 8, 6]
# Una sotto-tabella (slice): prime 2 righe, prime 3 colonne
print(voti_classe[:2, :3]): (i due punti)?Il simbolo : dentro le parentesi quadre significa "tutti".
voti_classe[:, 0] → leggiamolo così: "prendi TUTTE le righe (ecco il :), ma solo la colonna 0".
Il risultato è un array con il primo voto di ogni studente: [7, 8, 6].
voti_classe[:2, :3]:2 → "dalla riga 0 alla riga 2 esclusa", quindi righe 0 e 1.
:3 → "dalla colonna 0 alla colonna 3 esclusa", quindi colonne 0, 1 e 2.
Il risultato è una sotto-tabella 2×3 (il "pezzo" in alto a sinistra della matrice).
voti_classe[:, 0] — prendo tutta la colonna 0
La matrice: Colonna 0
[7, 8, 6, 9 ] → 7
[8, 7, 7.5, 8.5] → 8
[6, 6.5, 7, 7 ] → 6
Risultato: [7, 8, 6]axisQuando hai una matrice e vuoi calcolare la media, devi dire a NumPy in quale direzione calcolarla. Vuoi la media di ogni studente (ogni riga)? O la media di ogni materia (ogni colonna)? Per questo esiste il parametro axis.
# Media di ogni RIGA (= media di ogni studente)
media_studenti = voti_classe.mean(axis=1)
print("Media per studente:", media_studenti)
# Media di ogni COLONNA (= media di ogni materia)
media_materie = voti_classe.mean(axis=0)
print("Media per materia:", media_materie)
# Media di TUTTO (nessun axis)
media_totale = voti_classe.mean()
print(f"Media totale: {media_totale:.2f}")axis?Questo è un concetto che confonde molti, quindi andiamo piano.
axis=1 → "calcola lungo le colonne", cioè orizzontalmente. Per ogni riga, prende tutti i valori delle colonne e ne fa la media. Il risultato è un valore per ogni riga (= un valore per studente).
axis=0 → "calcola lungo le righe", cioè verticalmente. Per ogni colonna, prende tutti i valori delle righe e ne fa la media. Il risultato è un valore per ogni colonna (= un valore per materia).
Nessun axis → calcola su TUTTI gli elementi dell'intera matrice.
mean(axis=1) — media per studente (per ogni riga)
Riga 0: [7, 8, 6, 9] → (7+8+6+9) / 4 = 7.50
Riga 1: [8, 7, 7.5, 8.5] → (8+7+7.5+8.5) / 4 = 7.75
Riga 2: [6, 6.5, 7, 7] → (6+6.5+7+7) / 4 = 6.63
Risultato: [7.50, 7.75, 6.63] ← un valore per ogni riga!mean(axis=0) — media per materia (per ogni colonna)
Col 0: [7, 8, 6] → (7+8+6) / 3 = 7.00
Col 1: [8, 7, 6.5] → (8+7+6.5) / 3 = 7.17
Col 2: [6, 7.5, 7] → (6+7.5+7) / 3 = 6.83
Col 3: [9, 8.5, 7] → (9+8.5+7) / 3 = 8.17
Risultato: [7.00, 7.17, 6.83, 8.17] ← un valore per ogni colonna!💡 Trucco per ricordare axis:
axis=0 → il risultato ha meno righe (le righe vengono "compresse").
axis=1 → il risultato ha meno colonne (le colonne vengono "compresse").
Le statistiche servono a riassumere un gruppo di numeri con pochi valori significativi. Invece di guardare 1000 numeri uno per uno, puoi usare queste funzioni per capire subito "come vanno le cose". Vediamole una per una, partendo dalle più semplici.
Useremo questi punteggi di un videogioco per tutti gli esempi:
import numpy as np
punteggi = np.array([1200, 1500, 980, 1750, 1320, 1100, 1680, 1050, 1420, 1290])Queste sono le più intuitive:
print("Minimo:", punteggi.min()) # 980 — il punteggio più basso
print("Massimo:", punteggi.max()) # 1750 — il punteggio più alto
print("Somma:", punteggi.sum()) # 13290 — tutti i punteggi sommatiLa media è il valore che otterresti se distribuissi equamente il totale tra tutti. Si calcola sommando tutti i valori e dividendo per quanti sono.
print("Media:", punteggi.mean()) # 1329.0Se 10 amici hanno guadagnato in totale 13290 punti e decidessero di redistribuirli equamente, ognuno avrebbe 1329 punti. Questa è la media!
Attenzione: la media è sensibile ai valori estremi. Se un amico avesse 50000 punti, la media salirebbe tantissimo anche se gli altri hanno punteggi bassi. Per questo esiste la mediana.
La mediana è il valore che sta esattamente nel mezzo quando ordini tutti i numeri dal più piccolo al più grande. Metà dei valori stanno sotto la mediana, metà stanno sopra.
print("Mediana:", np.median(punteggi)) # 1305.0Immagina 5 persone: 4 guadagnano 1000€/mese e 1 guadagna 100.000€/mese.
Media: (4×1000 + 100000) / 5 = 20.800€ — sembra che tutti siano ricchi!
Mediana: 1000€ — molto più rappresentativa della realtà!
La mediana è più affidabile quando ci sono valori estremi che "distorcono" la media.
La deviazione standard (abbreviata "std" o "dev. std.") ti dice quanto i valori si allontanano dalla media. In altre parole: i dati sono tutti simili tra loro, oppure sono molto diversi?
print("Deviazione standard:", punteggi.std()) # ~244.6Immagina due classi che fanno lo stesso compito:
Classe A — voti: [6, 6, 7, 7, 7, 7, 8, 8]
Media = 7, Dev. Std = 0.7 (piccola) → tutti hanno voti simili, raggruppati attorno al 7.
Classe B — voti: [3, 4, 5, 7, 7, 9, 10, 10]
Media = 6.9, Dev. Std = 2.5 (grande) → i voti sono molto diversi tra loro, c'è chi va malissimo e chi benissimo.
La media è quasi uguale, ma la deviazione standard ti dice che la Classe B ha risultati molto più "sparsi"!
1. Calcoli la media dei dati.
2. Per ogni valore, calcoli quanto è lontano dalla media (la differenza).
3. Elevi al quadrato ogni differenza (per eliminare i segni negativi).
4. Calcoli la media di questi quadrati → questa è la varianza.
5. Fai la radice quadrata della varianza → questa è la deviazione standard.
Non devi calcolarla a mano: punteggi.std() fa tutto per te! L'importante è capire cosa significa il risultato.
La varianza è semplicemente la deviazione standard al quadrato. Misura la stessa cosa (quanto i dati sono sparsi), ma con una scala diversa.
print("Varianza:", punteggi.var()) # ~59781
# Relazione: varianza = (deviazione standard) al quadrato
# E deviazione standard = radice quadrata della varianza
print("Verifica:", punteggi.std() ** 2) # Uguale alla varianza!💡 Quando usare varianza vs deviazione standard?
Nella pratica si usa quasi sempre la deviazione standard perché ha la stessa unità di misura dei dati originali (es. se i dati sono in cm, la dev.std è in cm). La varianza è in cm² — meno intuitiva. Ma entrambe dicono la stessa cosa: più sono grandi, più i dati sono "sparsi".
Il percentile ti dice: "sotto quale valore cade una certa percentuale dei dati?". È come mettere tutti i dati in fila dal più piccolo al più grande e poi trovare il punto che separa una certa porzione.
print("25° percentile:", np.percentile(punteggi, 25)) # ~1087.5
print("50° percentile:", np.percentile(punteggi, 50)) # = mediana!
print("75° percentile:", np.percentile(punteggi, 75)) # ~1545.0Immagina 100 studenti ordinati dal voto più basso al più alto:
25° percentile → il voto dello studente in posizione 25. Il 25% degli studenti ha un voto uguale o inferiore a questo.
50° percentile → il voto dello studente in posizione 50 (metà classe). Questo è uguale alla mediana!
75° percentile → il voto dello studente in posizione 75. Solo il 25% degli studenti ha un voto superiore a questo.
Se il tuo voto è al 90° percentile, significa che hai fatto meglio del 90% degli studenti! 🎉
print("Posizione del minimo:", punteggi.argmin()) # 2
print("Posizione del massimo:", punteggi.argmax()) # 3.argmin() e .argmax()Queste funzioni non restituiscono il valore minimo/massimo, ma la sua posizione (indice) nell'array.
Nell'esempio: punteggi.argmin() restituisce 2 perché il valore più piccolo (980) si trova in posizione 2 (ricorda: si conta da 0!).
Per ottenere il valore dalla posizione: punteggi[punteggi.argmin()] → punteggi[2] → 980.
Alcune funzioni si chiamano sull'array (col punto): punteggi.min(), punteggi.mean(), punteggi.std()
Altre si chiamano su NumPy passando l'array tra parentesi: np.median(punteggi), np.percentile(punteggi, 25)
Non c'è una logica precisa: semplicemente sono state implementate in modo diverso. L'importante è sapere come usarle!
Questa è una delle funzionalità più potenti (e inizialmente più confuse!) di NumPy. Permette di selezionare solo alcuni elementi di un array in base a una condizione. Andiamo per gradi.
Quando confronti un array con un numero (usando >, <, >=, <=, ==), NumPy confronta ogni singolo elemento e crea un nuovo array fatto di True e False:
import numpy as np
temperature = np.array([18, 22, 25, 15, 30, 28, 20, 35, 12, 27])
# Chiediamo: quali temperature sono maggiori di 25?
risultato = temperature > 25
print("temperature > 25 dà:", risultato)temperature > 25:
NumPy prende OGNI elemento e lo confronta con 25:
18 > 25? → False
22 > 25? → False
25 > 25? → False (25 NON è maggiore di 25, è solo uguale)
15 > 25? → False
30 > 25? → True ✓
28 > 25? → True ✓
20 > 25? → False
35 > 25? → True ✓
12 > 25? → False
27 > 25? → True ✓
Risultato: [False, False, False, False, True, True, False, True, False, True]Questo array di True/False si chiama maschera booleana. Da solo non serve a molto, ma il passo dopo è dove avviene la magia!
Ora arriva il trucco fondamentale: puoi mettere la maschera dentro le parentesi quadre dell'array originale. NumPy terrà solo gli elementi dove la maschera vale True!
# Modo LUNGO (in due passaggi, per capire bene):
maschera = temperature > 25 # Passo 1: crea la maschera
temp_calde = temperature[maschera] # Passo 2: filtra con la maschera
print("Temperature calde:", temp_calde) # [30, 28, 35, 27]
# Modo COMPATTO (tutto in una riga):
temp_calde = temperature[temperature > 25]
print("Temperature calde:", temp_calde) # [30, 28, 35, 27]temperature[temperature > 25]Questa riga sembra strana perché "temperature" compare due volte, ma sono due operazioni distinte:
1. Prima Python esegue ciò che c'è DENTRO le parentesi quadre: temperature > 25. Questo produce la maschera: [False, False, False, False, True, True, False, True, False, True]
2. Poi NumPy usa quella maschera come filtro: temperature[maschera]. Prende dall'array originale SOLO i valori dove la maschera dice True.
Risultato: [30, 28, 35, 27] — solo i 4 valori che superano 25!
Array originale — i valori verdi passano il filtro (> 25), quelli sbiaditi vengono esclusi:
Dopo il filtro rimangono solo:
Ricorda: Python tratta True come 1 e False come 0. Quindi se fai la somma di una maschera, ottieni il conteggio dei True!
n_calde = np.sum(temperature > 25)
print(f"Giorni caldi (>25°): {n_calde}") # 4
n_fredde = np.sum(temperature <= 20)
print(f"Giorni freddi (≤20°): {n_fredde}") # 5np.sum(temperature > 25) conta i True?temperature > 25 produce: [False, False, False, False, True, True, False, True, False, True]
np.sum() fa la somma. Siccome True = 1 e False = 0:
0 + 0 + 0 + 0 + 1 + 1 + 0 + 1 + 0 + 1 = 4
Puoi combinare condizioni con & (AND = entrambe vere) e | (OR = almeno una vera). Ogni condizione deve stare tra parentesi tonde!
# Temperature tra 20 e 30 (ENTRAMBE le condizioni vere)
miti = temperature[(temperature >= 20) & (temperature <= 30)]
print("Miti (20-30):", miti) # [22, 25, 30, 28, 20, 27]
# Temperature sotto 15 OPPURE sopra 30
estreme = temperature[(temperature < 15) | (temperature > 30)]
print("Estreme:", estreme) # [12, 35]⚠️ Attenzione alle parentesi!
Quando combini condizioni con & o |, ogni condizione deve avere le sue parentesi:
✅ (temperature >= 20) & (temperature <= 30)
❌ temperature >= 20 & temperature <= 30 → Errore!
np.where()np.where() funziona come un "if-else" applicato a tutto l'array contemporaneamente:
# Sintassi: np.where(condizione, valore_se_true, valore_se_false)
# "Se > 30, metti 30. Altrimenti, tieni il valore originale."
temp_limitate = np.where(temperature > 30, 30, temperature)
print("Limitate:", temp_limitate)np.where(temperature > 30, 30, temperature)
Per ogni elemento chiede: "è maggiore di 30?"
18 > 30? No → tieni 18
22 > 30? No → tieni 22
25 > 30? No → tieni 25
15 > 30? No → tieni 15
30 > 30? No → tieni 30 (30 non è MAGGIORE di 30)
28 > 30? No → tieni 28
20 > 30? No → tieni 20
35 > 30? Sì → metti 30 (il 35 viene sostituito!)
12 > 30? No → tieni 12
27 > 30? No → tieni 27
Risultato: [18, 22, 25, 15, 30, 28, 20, 30, 12, 27]np.select()np.select() è come un "if / elif / else" applicato a tutto l'array. Definisci una lista di condizioni e una lista di etichette corrispondenti:
# Classificare le temperature in categorie
condizioni = [
temperature < 15, # Condizione 1
(temperature >= 15) & (temperature < 25), # Condizione 2
temperature >= 25 # Condizione 3
]
etichette = ["Freddo", "Mite", "Caldo"] # Un'etichetta per ogni condizione
classificazione = np.select(condizioni, etichette)
print("Classificazione:", classificazione)np.select(condizioni, etichette)Per ogni elemento dell'array, NumPy controlla le condizioni in ordine:
1. È < 15? Se sì → "Freddo"
2. È tra 15 e 25? Se sì → "Mite"
3. È >= 25? Se sì → "Caldo"
Esempio: 18° → non è < 15, MA è tra 15 e 25 → "Mite"
Esempio: 35° → non è < 15, non è tra 15 e 25, MA è >= 25 → "Caldo"
import numpy as np
array = np.arange(1000000)
result = []
for x in array:
result.append(x * 2)
result = np.array(result)import numpy as np
array = np.arange(1000000)
result = array * 2
# 100x più veloce! ⚡import numpy as np
result = []
for i in range(1000000):
result.append(i ** 2)
result = np.array(result)import numpy as np
result = np.zeros(1000000)
for i in range(1000000):
result[i] = i ** 2💡 Ma la soluzione MIGLIORE è sempre evitare il loop!
In questo caso: result = np.arange(1000000) ** 2. Una riga, nessun loop, velocità massima!
import numpy as np
array = np.array([3, 7, 1, 9, 4])
somma = 0
for x in array:
somma += x
media = somma / len(array)import numpy as np
array = np.array([3, 7, 1, 9, 4])
media = array.mean()
# Semplice e veloce!Crea un array con questi 10 voti: np.array([5, 7, 8, 4, 6, 9, 5.5, 7, 8.5, 6])
np.sum()argmin() e argmax()Crea un array di 15 temperature con np.linspace(-10, 40, 15):
fahrenheit = celsius * 9/5 + 32np.where() per sostituire le temperature Celsius negative con 0Crea una matrice 4×3 (4 settimane, 3 prodotti) con vendite inventate:
.sum(axis=0).sum(axis=1)Simula 1000 lanci di due dadi:
dado1 = np.random.randint(1, 7, size=1000) e dado2 ugualesomme = dado1 + dado2np.sum(somme == 7)Crea due matrici 3×3 con np.random.randint(1, 10, size=(3,3)):
.max(axis=1)C = np.where(A > B, A, B)Genera 100 altezze: altezze = np.random.normal(loc=170, scale=10, size=100)
np.sum(altezze > 180)z = (altezze - altezze.mean()) / altezze.std()Congratulazioni! Hai imparato a usare NumPy! 🎉 Ecco cosa sai fare ora:
import numpy as npnp.array(), np.zeros(), np.ones(), np.arange(), np.linspace()[riga, colonna] e : per "tutti"axis=0 (verticale, per colonna) e axis=1 (orizzontale, per riga).mean(), .min(), .max(), .std(), np.median()array[array > valore] seleziona solo gli elementi che rispettano la condizione🎯 Perché NumPy è importante?
NumPy è la FONDAZIONE di tutto il mondo Data Science e Machine Learning in Python:
🎯 Prossima Lezione: Matplotlib
Nel prossimo modulo imparerai a creare grafici professionali per visualizzare i tuoi dati! 📊✨