Machine Learning Con Python 3
Machine Learning Con Python 3
- Un algoritmo che sulla base delle informazioni, reagisce in modo diverso in base ai diversi input,
date regole specifiche precedentemente assegnate:
Immaginiamo di creare un algoritmo sui mercati e di dover testare una strategia di acquisto long-
term sul Nasdaq. Mettiamo che stiamo cercando di testare una strategia dove ogni volta che il
prezzo superi la 2ª deviazione del prezzo in negativo (per chi non è comune al settore lo potremmo
semplificare come un movimento insolito del prezzo verso il basso) si acquisti. Potremmo usare
come etichetta il raggiungimento della seconda deviazione da parte del prezzo, e impostare un
acquisto proporzionale alla “discesa” del prezzo.
2) Addestramento e scelta di un modello predittivo: Dato che non tutti i modelli devono
risolvere lo stesso tipo di problemi, sarà necessario addestrarlo rispetto uno specifico
problema. Possiamo mettere in relazione questo concetto a un detto popolare “suppongo sia
normale avendo a disposizione solo un martello, trattare ogni cosa come un chiodo”
(Abraham Maslow, 1966). Sarà necessario quindi confrontare differenti algoritmi col fine di
trovare l’algoritmo che offre il comportamento migliore.
3) Misurazione dell’errore e predizioni su istanze mai viste: Per costruire un modello predittivo
si parte da dati puliti e numerici, trasformati in una matrice equilibrata; si sceglie la forma
del modello (lineare, ad albero, rete, ecc.), si definisce come misurare l’errore (cosa
definiamo come giusto e cosa come sbagliato), e si ottimizzano i parametri affinché l’errore
sia minimo. Durante l’addestramento si controlla che il modello non impari solo i dati visti,
ma che riesca a operare anche su dati nuovi (overfitting) e, confrontando diverse opzioni, si
sceglie quello che funziona meglio sui dati nuovi, pronto per fare predizioni affidabili.
Neuroni Artificiali
Un neurone artificiale è un piccolo calcolatore che prende dei numeri in input e produce un numero
in output. Si ispira vagamente ai neuroni biologici, ma in realtà è solo matematica.
Ogni input ha un “peso” [w] che dice quanto è importante.
Esempio: se il neurone riceve Età e Reddito, potrebbe pesare di più il Reddito se è più rilevante, un
esempio potrebbe essere: input1×peso1 + input2×peso2 + …
Il Perceptron è un tipo di neurone artificiale semplice, inventato da Frank Rosenblatt negli anni
’50. Questo è usato per classificare i dati in due categorie (ad esempio “sì” o “no”, “rosso” o
“blu”), e attualmente è la base delle reti neurali moderne, anche se molto più semplice.
Provando a dividere il funzionamento a fasi uscirebbe una cosa di questo tipo:
1️) Il perceptron riceve diversi numeri come informazioni in ingresso. Ogni numero rappresenta
una caratteristica del problema. Ad esempio, se vuoi decidere se portare l’ombrello, gli input
potrebbero essere: “probabilità di pioggia” e “nuvolosità”.
2️) Dare peso agli input. Non tutti gli input sono uguali. Il perceptron assegna un peso a ciascun
input, cioè quanto quell’informazione conta nella decisione. Più il peso è grande, più
quell’informazione “spinge” la decisione.
Ad esempio, la probabilità di pioggia potrebbe avere peso alto, la nuvolosità un po’ meno.
3️) Il perceptron fa una somma di tutti gli input moltiplicati per i loro pesi, e aggiunge una sorta di
“spinta extra” chiamata bias. Questo totale indica quanto il perceptron è “convinto” di dire sì o no.
Poi confronta questo totale con una soglia:
Se supera la soglia → output = 1 (ad esempio: “porto l’ombrello”)
Se non supera la soglia → output = 0 (“non lo porto”)
In altre parole, decide come una bilancia: pesa tutto, somma, e decide se l’equilibrio pende da una
parte o dall’altra.
4) imparare dagli errori
Se il perceptron sbaglia la decisione: Guarda quanto si è sbagliato
Aggiusta i pesi degli input in modo che la prossima volta possa fare meglio
Ripete questo processo molte volte con dati diversi finché non impara a classificare correttamente
tutti i casi se possibile.
È da notare che il perceptron può risolvere solo problemi lineari, cioè quelli che se posti
graficamente è possibile tracciare una linea che divide le due categorie, come nella seconda foto.
Regressione Logistica
La regressione logistica prende input numerici (come nuvolosità e probabilità di pioggia), li
combina con pesi e bias, applica la sigmoide per ottenere una probabilità e decide la classe finale.
Rispetto al perceptron, l’output è continuo e probabilistico; rispetto ad Adaline, lavora su
classificazione invece che su stima lineare. Con Scikit-learn, tutti i calcoli di output, probabilità,
aggiornamento pesi tramite SGD e gestione delle epoche sono fatti automaticamente, mentre noi
possiamo concentrarci su pre-elaborazione, scelta del modello e interpretazione dei risultati,
rendendo l’approccio scalabile a dataset grandi proprio come negli esempi precedenti dell’ombrello
e di Adaline.
Nel perceptron, la somma pesata degli input viene confrontata con una soglia fissa. Se la supera, il
modello decide di portare l’ombrello, altrimenti no. Il risultato è una decisione netta, senza
sfumature o incertezze. Il perceptron impara modificando i pesi solo quando sbaglia la decisione,
quindi il suo apprendimento è brusco e discontinuo. Questo lo rende semplice e intuitivo, ma poco
adatto a situazioni ambigue, come quando il cielo è solo parzialmente nuvoloso.
Adaline usa la stessa somma pesata, ma non applica subito una soglia. Il valore che produce è
continuo e può essere interpretato come una misura di quanto le condizioni meteo spingano verso la
scelta di portare l’ombrello. Durante l’addestramento, Adaline aggiorna sempre i pesi in base
all’errore, anche quando la previsione è solo leggermente sbagliata, rendendo l’apprendimento più
stabile rispetto al perceptron. Tuttavia, il valore prodotto non è una probabilità e non ha limiti
naturali, quindi serve comunque una soglia esterna per prendere una decisione finale.
La regressione logistica parte dallo stesso calcolo di Adaline, ma applica una funzione sigmoide che
trasforma il risultato in un numero compreso tra zero e uno. Questo numero rappresenta
direttamente la probabilità che serva l’ombrello. In questo modo il modello non dice solo se portarlo
o no, ma quanto è probabile che sia necessario. La decisione finale viene presa applicando una
soglia, di solito 0.5, ma l’informazione probabilistica rimane disponibile. L’apprendimento avviene
correggendo i pesi in modo graduale, minimizzando una funzione di errore specifica per la
classificazione, ed è per questo che la regressione logistica è molto usata nei problemi reali.
Quando questi modelli vengono usati in pratica con librerie come Scikit-learn, il meccanismo di
apprendimento è lo stesso concettualmente, ma viene eseguito in modo efficiente tramite la discesa
stocastica del gradiente. I pesi vengono aggiornati un esempio alla volta, permettendo di lavorare
anche con dataset molto grandi. La differenza fondamentale, quindi, non sta nella struttura
matematica di base, che è simile per tutti, ma nel significato dell’output: il perceptron prende una
decisione secca, Adaline fornisce una valutazione continua, mentre la regressione logistica
restituisce una probabilità interpretabile, che rende il modello più flessibile e realistico per problemi
decisionali come quello dell’ombrello.
Nella regressione logistica non basta indovinare la classe giusta, l’obiettivo è assegnare una
probabilità sensata. Questo è il primo grande salto rispetto al perceptron. Dire “ombrello sì” quando
piove è corretto, ma dire “ombrello sì con probabilità 0.99” quando in realtà non piove è una
pessima previsione, anche se la classe sarebbe formalmente giusta. La regressione logistica tiene
conto proprio di questo.
Il modello prende gli input, come nuvolosità e probabilità di pioggia, e fa quello che fanno tutti i
modelli lineari: li combina con dei pesi e aggiunge un bias. Il risultato di questa combinazione è un
numero reale qualsiasi, che da solo non ha ancora un significato probabilistico. A questo punto
entra in gioco la funzione sigmoide. La sigmoide non serve a “decidere”, ma a reinterpretare quel
numero come probabilità, comprimendolo tra zero e uno. Valori molto negativi diventano
probabilità vicine a zero, valori molto positivi diventano probabilità vicine a uno, valori intorno a
zero diventano probabilità intermedie. Questo passaggio è fondamentale: è qui che il modello
smette di essere solo un classificatore lineare e diventa un modello probabilistico.
Una volta ottenuta la probabilità, il modello la confronta con ciò che è realmente successo. Se in
quella giornata hai portato l’ombrello, il valore vero è uno; se non l’hai portato, è zero. La funzione
di costo logistico misura quanto è coerente la probabilità prevista con il risultato reale. Se il modello
assegna una probabilità alta a qualcosa che poi non accade, la penalità è molto grande. Questo
perché il modello era “sicuro” e ha sbagliato. Se invece assegna una probabilità intermedia e
sbaglia, la penalità è più bassa, perché stava esprimendo incertezza. Questo è il motivo per cui la
log-loss non punisce tutti gli errori allo stesso modo: punisce soprattutto le certezze sbagliate.
Ora veniamo all’apprendimento vero e proprio. Il modello vuole ridurre questo costo, cioè vuole
produrre probabilità che siano coerenti con la realtà. Per capire come farlo, si chiede: “quanto ha
influito ciascun peso sull’errore che ho appena commesso?”. Questa domanda è il gradiente. Il
gradiente dice se aumentando o diminuendo un certo peso il costo aumenterebbe o diminuirebbe. Se
un peso ha spinto la probabilità nella direzione sbagliata, il gradiente segnala che va ridotto; se ha
aiutato, segnala che va rafforzato. La discesa del gradiente è semplicemente il meccanismo che usa
questa informazione per correggere i pesi passo dopo passo.
Nella versione stocastica, questo processo avviene usando un esempio alla volta. Il modello vede
una giornata, fa una previsione, misura l’errore, aggiorna subito i pesi, poi passa alla giornata
successiva. Non aspetta di vedere tutti i dati insieme. Questo rende l’apprendimento più reattivo e
adatto a grandi quantità di dati. È come imparare dall’esperienza giorno per giorno, invece che
aspettare la fine dell’anno per fare un bilancio.
Torniamo all’ombrello per chiudere il cerchio. Se il modello vede una giornata molto nuvolosa e
con alta probabilità di pioggia, ma assegna una probabilità bassa all’uso dell’ombrello, la funzione
di costo reagisce con un errore elevato. Questo errore spinge ad aumentare i pesi legati a nuvolosità
e pioggia. Se invece il modello assegna una probabilità alta in una giornata effettivamente piovosa,
il costo è basso e i pesi cambiano poco. Ripetendo questo processo molte volte, il modello non
impara solo “da che parte sta il confine”, come fa il perceptron, ma impara come cambia la
probabilità nello spazio degli input. È per questo che si dice che la regressione logistica impara una
superficie di probabilità e non solo una linea di separazione.
L’Overfitting
L’overfitting succede quando un modello impara troppo bene i dati di addestramento, al punto da
memorizzarli, ma perde la capacità di generalizzare su dati nuovi. In altre parole, il modello non sta
imparando la regola generale che lega input e output, ma sta adattando i pesi per spiegare anche il
rumore, le eccezioni e gli errori presenti nei dati di training. Quando poi vede dati nuovi, le sue
previsioni peggiorano.
Riprendendo l’esempio dell’ombrello, un modello in overfitting non impara una regola del tipo “più
nuvoloso e più alta è la probabilità di pioggia, più conviene portare l’ombrello”, ma impara dettagli
troppo specifici come “in quella giornata particolare con nuvolosità media e pioggia 0.47 non ho
portato l’ombrello”. Queste regole sono vere per il passato, ma inutili per il futuro.
L’overfitting è più probabile quando il modello è troppo complesso rispetto alla quantità di dati,
quando i dati sono rumorosi o quando il modello viene addestrato troppo a lungo. Anche modelli
semplici come la regressione logistica possono andare in overfitting se hanno molte variabili o se i dati
sono pochi e poco rappresentativi. L’opposto dell’overfitting è l’underfitting, in cui il modello è
troppo semplice e non riesce nemmeno a catturare la struttura di base dei dati.
Dal punto di vista della funzione di costo, durante l’addestramento il costo sui dati di training continua
a diminuire, ma quello sui dati nuovi o di validazione smette di migliorare o addirittura
aumenta. Questo è il segnale classico che il modello sta iniziando a memorizzare invece di imparare. In
termini di probabilità, il modello diventa troppo sicuro delle sue previsioni sul training set, assegnando
probabilità estreme anche quando non dovrebbe.
Per evitare l’overfitting si usano varie strategie. La più importante è la regolarizzazione, che aggiunge
una penalità ai pesi troppo grandi, costringendo il modello a preferire soluzioni più semplici e stabili.
Un’altra strategia è fermare l’addestramento prima che il modello inizi a sovra-adattarsi, osservando le
prestazioni su un set di validazione. Anche avere più dati o meno variabili aiuta, perché rende più
difficile per il modello “imparare a memoria”.
Il collegamento con Scikit-learn è diretto: quando usi modelli come la regressione logistica, la
regolarizzazione è attiva di default proprio per prevenire l’overfitting. Anche se non la vedi
esplicitamente, la libreria sta già limitando la complessità del modello mentre ottimizza i pesi con la
discesa del gradiente.
L’idea centrale delle Support Vector Machine (SMV) non è stimare una probabilità come nella
regressione logistica, né semplicemente separare le classi come fa il perceptron, ma trovare il
confine di decisione più “robusto” possibile. Robusto significa che non basta separare
correttamente i dati di training: il confine deve essere il più lontano possibile dai punti di entrambe
le classi. Questa distanza si chiama margine, e massimizzarla è il vero obiettivo delle SVM.
Riprendiamo ancora l’esempio dell’ombrello. Immagina di disegnare su un piano i giorni in cui hai
portato l’ombrello e quelli in cui non l’hai portato, usando nuvolosità e probabilità di pioggia come
assi. Ci sono infinite rette che separano i due gruppi di punti. Il perceptron si accontenta di trovarne
una qualunque che non sbagli. La regressione logistica ne trova una che produce buone probabilità.
La SVM invece cerca quella retta che lascia la “zona di sicurezza” più ampia possibile tra i due
gruppi. Più questa zona è larga, meno il modello è sensibile a piccole variazioni o rumore nei dati, e
quindi meno tende all’overfitting.
Il margine è definito come la distanza tra la retta di separazione e i punti più vicini a essa. Questi
punti speciali si chiamano support vectors. Sono pochissimi rispetto al totale dei dati, ma sono gli
unici che contano davvero: se sposti un punto lontano dal confine, la soluzione non cambia; se
sposti un support vector, il confine cambia. Questo è un altro aspetto cruciale delle SVM: il modello
finale dipende solo da una piccola parte dei dati.
Rispetto a quanto hai visto prima, la differenza concettuale è forte. Il perceptron guarda solo se un
punto è dalla parte giusta o sbagliata. La regressione logistica guarda quanto è probabile che un
punto appartenga a una classe. La SVM guarda quanto è lontano dal confine, e costruisce il
modello per massimizzare questa distanza minima. È per questo che si dice che la SVM implementa
il principio della massimizzazione del margine: invece di adattarsi ai dati, cerca la separazione più
stabile possibile.
Nel riquadro Perceptron (in alto a sinistra) si vede una linea netta chiamata “confine netto”. Il
perceptron decide in modo secco: da una parte sì ombrello, dall’altra no. Non esistono sfumature né
probabilità. Se un punto cade a destra della linea, la decisione è “ombrello”, se cade a sinistra è
“niente ombrello”. Questo rende il modello semplice ma rigido: basta poco per cambiare
completamente la decisione.
Nel riquadro Adaline (in alto a destra) la linea di separazione esiste ancora, ma attorno a essa
compare una zona sfumata colorata. Questo significa che Adaline non ragiona solo in termini di
giusto/sbagliato, ma considera quanto è lontano un punto dalla linea. Più un punto è verso il rosso,
più il modello è “convinto” di prendere l’ombrello; più è verso il blu, più è convinto del contrario.
Qui l’apprendimento è più stabile perché l’errore viene misurato in modo continuo.
Nel riquadro Regressione Logistica (in basso a sinistra) la linea non è più solo un confine, ma una
soglia di probabilità, indicata come “soglia 0.5”. La zona colorata rappresenta una vera mappa di
probabilità: vicino al blu la probabilità di prendere l’ombrello è bassa, vicino al rosso è alta. Un
punto vicino alla linea non è semplicemente classificato, ma ha una probabilità vicina al 50%.
Questo modello non dice solo “sì o no”, ma “quanto è probabile che tu prenda l’ombrello”.
Nel riquadro SVM (in basso a destra) si vede invece una linea centrale e due linee tratteggiate
parallele: questo è il margine. La SVM non cerca solo di separare i punti, ma di farlo nel modo più
robusto possibile, massimizzando la distanza tra le classi. I punti cerchiati sono i vettori di
supporto, cioè i giorni critici più vicini al confine: sono loro che determinano la posizione della
linea. Tutti gli altri punti contano meno o per niente.
Qui entra in gioco il kernel. L’idea chiave è questa: invece di forzare una separazione complicata
nello spazio originale, la SVM trasforma implicitamente i dati in uno spazio di dimensione più
alta, dove la separazione diventa semplice e lineare. Per esempio, da un piano si può passare a uno
spazio tridimensionale, o a uno spazio con moltissime dimensioni. In questo nuovo spazio, ciò che
prima era una curva o una forma complicata diventa un iperpiano.
È importante capire che la SVM non costruisce esplicitamente questo spazio più grande. Non
calcola davvero nuove coordinate gigantesche. Usa invece una scorciatoia matematica chiamata
kernel trick: una funzione kernel permette di calcolare direttamente il prodotto scalare nello spazio
trasformato, senza mai rappresentarlo. In pratica, la SVM si comporta come se i dati fossero stati
“sollevati” in uno spazio più ricco, ma senza pagarne il costo computazionale.
Torniamo all’esempio dell’ombrello. Immagina che le decisioni non dipendano solo linearmente da
nuvolosità e probabilità di pioggia, ma da una combinazione più complessa: per esempio prendi
l’ombrello solo quando entrambe sono alte, ma non quando una è alta e l’altra bassa. Sul piano
questo disegna una forma curva, impossibile da separare con una retta. Applicando un kernel, la
SVM introduce nuove dimensioni implicite che catturano queste interazioni. In quello spazio più
alto, esiste un iperpiano che separa bene i giorni “ombrello” dai giorni “no ombrello”. Quando poi
riporti la decisione nello spazio originale, l’iperpiano appare come una frontiera curva.
Diversi kernel corrispondono a diversi modi di arricchire lo spazio. Il kernel polinomiale permette
separazioni che tengono conto di potenze e interazioni tra variabili. Il kernel RBF (gaussiano) crea
regioni di influenza attorno ai punti e consente confini molto flessibili. Il kernel lineare, invece, non
trasforma nulla ed è equivalente a una SVM classica a margine massimo.
Il punto cruciale è che, anche con i kernel, la filosofia della SVM non cambia: si cerca sempre un
iperpiano che massimizza il margine. Cambia solo lo spazio in cui questo iperpiano vive. È per
questo che le SVM con kernel riescono a risolvere problemi complessi senza perdere il controllo
sull’overfitting: il margine e i parametri del kernel regolano quanto il modello può piegarsi ai dati.
Ecco 2 visioni della stessa separazione, la prima sotto sempre 2 dimensioni, la seconda aumentando
di una dimensione.