La regressione è uno dei due principali problemi dell’apprendimento supervisionato, la branca del machine learning che vuole insegnare ai computer a risolvere un determinato problema mostrandogli come questo problema è stato già risolto in passato.

Intuitivamente la regressione consente di trovare la relazione tra input e output, in modo da predire output futuri avendo a disposizione solamente l’input.

Ad esempio, avendo a disposizione un set di dati contenente le specifiche di diversi smartphone e il relativo prezzo di listino, potremmo utilizzare la regressione per predire a che prezzo potrà essere venduto un nuovo smartphone basandosi sulle sue specifiche.

Altri esempi molto più comuni sono il provare a predire il valore futuro di un titolo in borsa in base ai valori passati, provare a predire l’affluenza di utenti al blog in base ai contenuti di un articolo che si vuole pubblicare o il numero di nuovi iscritti in base a delle campagne di advertising in pianificazione.

Matematicamente la regressione può essere intesa come il trovare la funzione che meglio approssima la relazione tra la variabile indipendente X (l’input) e la variabile dipendente Y (l’output). Nel caso di una regressione lineare questa funzione è un semplice polinomio.

Graficamente questa relazione lineare può essere rappresentata come una retta che passa il più vicino possibile a tutti i punti costituiti da input X e output Y.

Predire il valore di un’abitazione

Per questo primo esempio utilizzeremo il popolarissimo Boston Housing Dataset, un dataset contenente diverse informazioni riguardo alcune alcune abitazioni nei dintorni di Boston.

Un dataset strutturato si può presentare in diversi formati: CSV, TSV, XML, HTTP, JSON, EXCEL eccetera, in ogni caso questo ha una struttura tabulare.

  • Una delle colonne della tabella è il valore che vogliamo addestrare il nostro modello a predire e prende il nome di target.
  • Tutte le altre colonne sono proprietà che possiamo potenzialmente usare per creare il nostro modello, purché abbiano una relazione con il target, e vengono chiamate features.

Pandas è una libreria Python sviluppata appositamente per chi lavora con i dati e mette a disposizione una particolare struttura dati chiamata DataFrame che si presta particolarmente bene a contenere dati in forma tabulare.

Carichiamo il Boston Housing Dataset all’interno di un DataFrame utilizzando la funzione read_csv, seguita dal metodo head del DataFrame per vedere le sue prime 5 righe.

import pandas as pd

boston = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data",
sep='\s+', #le colonne all'interno del file sono separate da un numero variabile di spazi, in questo caso dobbiamo utilizzare l'espressione regolare '\s+'
names=["CRIM","ZN","INDUS","CHAS","NOX","RM","AGE","DIS","RAD","TAX","PRATIO","B","LSTAT","MEDV"]) # impostiamo dei nomi per le colonne

boston.head() # passando un valore n a questo metodo stamperemo i primi n esempi del dataset

Il DataFrame avrà questa struttura:

La colonna che abbiamo denominato MEDV contiene il valore dell’abitazione in $1000 dollari (ad esempio un MEDV di 24 corrisponde a 24.000$) ed è il nostro target.

 

Regressione lineare semplice

Una regressione lineare semplice utilizza un’unica feature per costruire il modello, nel nostro caso utilizzeremo solo il numero di stanze, cioè la colonna che abbiamo denominato RM.

Estraiamo la feature RM e il target MEDV e salviamo i valori all’interno di due array numpy che ci serviranno per l’addestramento.

X = boston[['RM']].values # con l'attributo values ottieniamo l'array
Y = boston["MEDV"].values

E’ buona pratica nel machine learning eseguire l’addestramento su un set di dati per poi verificare i risultati delle sue predizioni con un altro set contente dati non visti durante l’addestramento.
Questo garantisce che il nostro modello è in grado di generalizzare su dati sconosciuti e quindi ha realmente “imparato” dai dati, piuttosto che limitarsi a memorizzare il set di addestramento, condizione conosciuta come overfitting.

Per fare questo dobbiamo suddividere il nostro dataset in due set distinti, uno da utilizzare unicamente per l’addestramento e un altro da utilizzare per il test, possiamo farlo utilizzando il metodo train_test_split di scikit-learn.

from sklearn.model_selection import train_test_split
X_train, X_test, Y_train, Y_test = train_test_split(X,Y, test_size=0.3, random_state=0)

Adesso abbiamo tutto ciò che ci serve per costruire il modello, facciamolo utilizzando la classe LinearRegression di scikit-learn:

  • con il metodo fit eseguiamo l’addestramento
  • con il metodo predict eseguiamo la predizione

Queste due semplici API sono comuni tra tutti i modelli definiti in scikit-learn, il ché rende il sostituire un modello con un altro estremamente semplice.

from sklearn.linear_model import LinearRegression

ll = LinearRegression()
ll.fit(X_train, Y_train) # passiamo i set di addestramento 
Y_pred_train = ll.predict(X_train) # eseguiamo la predizione sul train set
Y_pred_test = ll.predict(X_test) # eseguiamo la predizione anche sul test set

Congratulazione ! Hai costruito il tuo primo modello di regressione e hai eseguito la tua prima predizione. Adesso bisogna vedere quanto buono è questo modello.
Per farlo dobbiamo definire una metrica che ci permetterà di misurare quanto le predizioni del modello si avvicinano ai valori corretti.
Una metrica semplice che fa proprio questo è l’errore quadratico medio (mean squadred error – MSE)

from sklearn.metrics import mean_squared_error

print("MSE train: %f" % mean_squared_error(Y_train, Y_pred_train))
print("MSE test: %f" % mean_squared_error(Y_test, Y_pred_test))

Il risultato dovrebbe essere circa 42.16 per il train set e 47.03 per il test set, come vanno interpretati ?

Estraendo la radice quadrata otteniamo un valore che indica mediamente di quanto si è sbagliato il modello. Nel nostro caso, il test set ha ottenuto un MSE di 47 la cui radice quadrata è circa 6.9, considerando che i prezzi delle case sono rappresentati in $1000 questo ci dice che in media il modello ha fatto cilecca per 6900$.

Una metrica più intuitiva è il coefficiente di indeterminazione (anche conosciuto come R-squared score), può essere inteso come una versione standardizzata del MSE e ritorna un punteggio compreso tra 0 e 1 che può essere letto in questo modo:

  • R2_score < 0.3 il modello è inutile.
  • 0.3 < R2_score < 0.5 il modello è scarso.
  • 0.5 < R2_score < 0.7 il modello è discreto.
  • 0.7 < R2_score < 0.9 il modello è buono.
  • 0.9 < R2_score < 1 il modello è ottimo.
  • R2_score = 1 molto probabilmente c’è un errore nel modello.
from sklearn.metrics import r2_score

print("R2 train: %f" % r2_score(Y_train, Y_pred_train))
print("R2 test: %f" % r2_score(Y_test, Y_pred_test))

Se hai fatto tutto correttamente dovresti ottenere un punteggio R-squared di circa 0.50 sul train set e 0.435 sul test set.

Il risultato non è così male considerando le poche informazioni che abbiamo utilizzato (solamente il numero di stanze), ma possiamo fare meglio !

Regressione lineare multipla

Una regressione lineare multipla è un modello che utilizza due o più features per l’addestramento.

Proviamo a predire il valore delle abitazioni utilizzando tutte le 13 features presenti nel nostro dataset, ricreiamo i nostri array con features e target, questa volta selezionando tutte le proprietà.

X = boston.drop("MEDV", axis=1).values # utilizzando drop rimuoviamo la colonna del prezzo e selezioniamo tutte le altre
Y = boston["MEDV"].values

X_train, X_test, Y_train, Y_test = train_test_split(X,Y, test_size=0.3, random_state=0)

Quando lavoriamo con più features dobbiamo essere sicuri che queste siano comprese in un range di valori comune, per far questo abbiamo due possibilità:

  • Normalizzazione: portiamo tutti i dati in un range compreso tra 0 e 1
  • Standardizzazione: convertiamo i dati in una distribuzione normale con media 0 e deviazione standard 1.

Standardizziamo l’array con le features utilizzando la classe StandardScaler di scikit-learn

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
X_train_std = ss.fit_transform(X_train)
X_test_std = ss.transform(X_test)

Adesso possiamo creare il modello esattamente come fatto prima…

from sklearn.linear_model import LinearRegression

ll = LinearRegression()
ll.fit(X_train_std, Y_train)
Y_pred_train = ll.predict(X_train_std)
Y_pred_test = ll.predict(X_test_std)

… e calcolare le metriche

print("MSE train: %f" % mean_squared_error(Y_train, Y_pred_train))
print("MSE test: %f" % mean_squared_error(Y_test, Y_pred_test))

print("R2 train: %f" % r2_score(Y_train, Y_pred_train))
print("R2 test: %f" % r2_score(Y_test, Y_pred_test))

Dovresti ottenere i seguenti risultati:

  • MSE del train set ≈ 19.96
  • MSE del test set ≈ 27.16
  • R2 del train set ≈ 0.76
  • R2 del test set ≈ 0.67

Come vedi il risultato è nettamente superiore rispetto a quanto ottenuto con un’unica feature, avendo più informazioni a disposizione l’algoritmo di machine learning è riuscito a individuare pattern migliori e quindi a eseguire predizioni migliori.

Infatti una cosa da tenere sempre a mente è che, spesso, nel machine learning la quantità ma soprattutto la qualità dei dati riveste un ruolo anche superiore a quello degli algoritmi stessi.

Trovi questo articolo in versione notebook eseguibile sulla repository Github dei tutorial di ProfessionAI.


Ti interessa il Machine Learning ? Se vuoi approfondire più nel dettaglio la regressione e altri argomenti come classificazione e clustering allora dai uno sguardo al nostro Corso Pratico sul Machine Learning con Python, disponbile su Udemy a soli 9.90 per un periodo di tempo limitato.

About Giuseppe Gullo

Cresciuto a pane e bit, ho cominciato a programmare a 13 anni, durante un periodo di convalescenza forzata dovuta ad un brutto incidente.

Durante la mia adolescenza ho utilizzato un mio approccio hacker all'apprendimento per passare da un argomento all'altro senza sosta, sviluppo web, programmazione software, sviluppo mobile per android ed iOS, sviluppo di videogame 2d e 3d con Unity.

Poco più che ventenne mi sono avvicinato all'intelligenza artificiale, ed è stato amore a prima vista.

Ho lavorato come sviluppatore indipendente e freelancer, creando diverse dozzine di servizi che hanno raggiunto centinaia di migliaia di persone in tutto il mondo.

Il mio life goal è riuscire a sfruttare le enormi potenzialità dell'AI per migliorare le condizioni di vita degli esseri umani.