Applicazioni di machine learning con Python
A cura di Ilaria Lombardi
Il machine learning
Nel mondo dell’intelligenza artificiale, il machine Learning è una delle tecnologie principali, che ha conosciuto un’evoluzione rapida negli ultimi anni, destando curiosità ma anche preoccupazione per i risultati ottenuti e le potenzialità future. Esso si occupa di sviluppare algoritmi che apprendono dai dati ed effettuano previsioni o prendono decisioni sulla base di quanto appreso. In altre parole, invece di scrivere un programma che esegua compiti specifici in modo deterministico, vengono forniti ai computer un insieme di dati e un algoritmo che li analizzi per estrarre da essi modelli o pattern. I dati, dunque, sono un esempio di come il sistema dovrebbe agire a fronte di diverse situazioni: compito del sistema è imparare come comportarsi in situazioni simili.
Esistono diverse tecniche di machine learning, ognuna con i suoi punti di forza e di debolezza: apprendimento supervisionato, non supervisionato e per rinforzo.
Nel caso dell’apprendimento supervisionato, ai sistemi vengono forniti dei dati già etichettati, ovvero associati a una risposta corretta. L'obiettivo del sistema è imparare a mappare gli input (i dati) agli output (le etichette). Esempi di apprendimento supervisionato includono la classificazione (per esempio, identificare se un'email è spam o meno) e la regressione (per esempio, prevedere il prezzo di un'azione societaria).
Al contrario, l’apprendimento non supervisionato parte da dati non etichettati. L'obiettivo del sistema è scoprire modelli o raggruppare i dati in modo autonomo. Un esempio di apprendimento non supervisionato è il clustering (per esempio, raggruppare i clienti in base alle loro abitudini di acquisto).
Infine, i sistemi di apprendimento per rinforzo imparano per tentativi ed errori interagendo con un ambiente. L'obiettivo del sistema è massimizzare una ricompensa o minimizzare una penalità. Esempi di apprendimento per rinforzo includono i robot che imparano a camminare o a giocare a un videogame.
Le applicazioni in cui è utilizzato il machine learning sono numerose, vediamone alcune:
Esistono diverse tecniche di machine learning, ognuna con i suoi punti di forza e di debolezza: apprendimento supervisionato, non supervisionato e per rinforzo.
Nel caso dell’apprendimento supervisionato, ai sistemi vengono forniti dei dati già etichettati, ovvero associati a una risposta corretta. L'obiettivo del sistema è imparare a mappare gli input (i dati) agli output (le etichette). Esempi di apprendimento supervisionato includono la classificazione (per esempio, identificare se un'email è spam o meno) e la regressione (per esempio, prevedere il prezzo di un'azione societaria).
Al contrario, l’apprendimento non supervisionato parte da dati non etichettati. L'obiettivo del sistema è scoprire modelli o raggruppare i dati in modo autonomo. Un esempio di apprendimento non supervisionato è il clustering (per esempio, raggruppare i clienti in base alle loro abitudini di acquisto).
Infine, i sistemi di apprendimento per rinforzo imparano per tentativi ed errori interagendo con un ambiente. L'obiettivo del sistema è massimizzare una ricompensa o minimizzare una penalità. Esempi di apprendimento per rinforzo includono i robot che imparano a camminare o a giocare a un videogame.
Le applicazioni in cui è utilizzato il machine learning sono numerose, vediamone alcune:
- identificare oggetti e persone all’interno di immagini e video;
- comprendere e generare il linguaggio umano;
- suggerire prodotti o servizi a utenti in base alle loro precedenti attività (recommender systems);
- rilevare le frodi: identificare transazioni fraudolente;
- eseguire diagnosi mediche: assistere i medici nella diagnosi di malattie.
La classificazione nel machine learning
La classificazione è uno dei compiti fondamentali del machine learning. Rientra nella categoria dell’apprendimento supervisionato e consiste nell’assegnare un'etichetta (label) o una classe o una categoria a un insieme di dati in base alle loro caratteristiche. In altre parole, serve a organizzare i dati in gruppi predefiniti in base alle loro caratteristiche. La classificazione può aiutare in diverse attività pratiche come, per esempio, riconoscere messaggi di spam o di frodi bancarie, classificare articoli di giornale per argomento o prevedere la possibilità che un paziente sviluppi una determinata malattia, come nel caso mostrato qui di seguito.
Consideriamo i dati che rappresentano la presenza di una malattia cardiovascolare in diversi pazienti:
In questo dataset, le prime sette colonne sono le caratteristiche o attributi (feature) che descrivono gli esemplari, mentre l’ultima colonna è l’etichetta (label o target), cioè la classe in cui collocare il singolo esemplare. In altre parole, le feature sono l’input del sistema e la label è l’output.
Ogni riga della tabella rappresenta un esempio da cui apprendere. Il paziente della prima riga è un uomo di 45 anni che ha una pressione sanguigna alta, livelli di glucosio e colesterolo elevati, fuma e non ha familiari con malattie cardiovascolari. Questa persona ha sviluppato una malattia cardiovascolare, come indicato nell’ultima colonna.
Se al sistema fosse richiesto di prevedere se un uomo con le sue stesse caratteristiche svilupperà una malattia cardiovascolare, la risposta del sistema dovrebbe essere Sì. Ma cosa dovrebbe rispondere se una caratteristica cambiasse? Se il livello di glucosio fosse normale, sarebbe ininfluente o determinante? Il sistema dovrebbe essere in grado di tenere conto dei dati su tutte le altre persone e da questi dedurre una risposta, anche e soprattutto nei casi non esattamente uguali a quelli da essi descritti. Per esempio, nella tabella non ci sono fumatori con livelli normali per i tre fattori pressione sanguigna, livello di glucosio, colesterolo, ma il sistema dovrebbe fornire una risposta considerando casi simili.
Consideriamo i dati che rappresentano la presenza di una malattia cardiovascolare in diversi pazienti:
In questo dataset, le prime sette colonne sono le caratteristiche o attributi (feature) che descrivono gli esemplari, mentre l’ultima colonna è l’etichetta (label o target), cioè la classe in cui collocare il singolo esemplare. In altre parole, le feature sono l’input del sistema e la label è l’output.
Ogni riga della tabella rappresenta un esempio da cui apprendere. Il paziente della prima riga è un uomo di 45 anni che ha una pressione sanguigna alta, livelli di glucosio e colesterolo elevati, fuma e non ha familiari con malattie cardiovascolari. Questa persona ha sviluppato una malattia cardiovascolare, come indicato nell’ultima colonna.
Se al sistema fosse richiesto di prevedere se un uomo con le sue stesse caratteristiche svilupperà una malattia cardiovascolare, la risposta del sistema dovrebbe essere Sì. Ma cosa dovrebbe rispondere se una caratteristica cambiasse? Se il livello di glucosio fosse normale, sarebbe ininfluente o determinante? Il sistema dovrebbe essere in grado di tenere conto dei dati su tutte le altre persone e da questi dedurre una risposta, anche e soprattutto nei casi non esattamente uguali a quelli da essi descritti. Per esempio, nella tabella non ci sono fumatori con livelli normali per i tre fattori pressione sanguigna, livello di glucosio, colesterolo, ma il sistema dovrebbe fornire una risposta considerando casi simili.
Classificazione con l’algoritmo K-Nearest Neighbors (KNN)
K-Nearest Neighbors è un semplice algoritmo di classificazione che si basa sul principio che gli oggetti simili tendono a trovarsi vicini nello spazio delle caratteristiche. Funziona calcolando la distanza tra i punti nel dataset e assegnando loro l'etichetta della maggioranza dei k punti più vicini.
Vediamo un esempio con due feature, che possiamo facilmente rappresentare sul piano cartesiano (Figura 1): una feature è rappresentata dalla x e l’altra dalla y. In altre parole, ogni punto nel piano è un esemplare e il colore rappresenta l’etichetta assegnatagli. Per semplicità ci limitiamo a un caso con due attributi, ma possiamo facilmente immaginare che, estendendo gli esemplari a tre feature, ci troveremmo in uno spazio tridimensionale e per un numero maggiore di feature in spazi multidimensionali.
Figura 1: esemplari classificati con tre diverse etichette (i colori)
Quando dobbiamo assegnare l’etichetta (ossia il colore) a un nuovo esemplare, possiamo scegliere quella dei suoi k punti più vicini.
Figura 2: classificazione del nuovo punto come azzurro con k = 1
Se consideriamo invece la situazione illustrata nella Figura 3, etichettiamo il nuovo punto come arancione, perché tale è il suo punto più vicino.
Figura 3: classificazione del nuovo punto come arancione con k = 1
Figura 4: classificazione per k = 3.
Nell’algoritmo KNN ci sono due parametri da considerare: il valore di k e la metrica per il calcolo della distanza. Negli esempi proposti abbiamo calcolato la distanza euclidea.
Come abbiamo visto, k definisce quanti punti vicini verranno controllati per determinare la classificazione di un nuovo punto. La scelta di k dipende in gran parte dai dati di input: i dati con più valori anomali o rumore probabilmente funzioneranno meglio con valori più elevati di k, che smorza quindi l’impatto di possibili anomalie. Inoltre, l’uso di un valore di k dispari permette di evitare pareggi nella classificazione.
Infine, spesso si ricorre al confronto delle prestazioni dell’algoritmo KNN con diversi valori di k, per selezionare poi quello ottimale per lo specifico set di dati.
Vediamo un esempio con due feature, che possiamo facilmente rappresentare sul piano cartesiano (Figura 1): una feature è rappresentata dalla x e l’altra dalla y. In altre parole, ogni punto nel piano è un esemplare e il colore rappresenta l’etichetta assegnatagli. Per semplicità ci limitiamo a un caso con due attributi, ma possiamo facilmente immaginare che, estendendo gli esemplari a tre feature, ci troveremmo in uno spazio tridimensionale e per un numero maggiore di feature in spazi multidimensionali.
Figura 1: esemplari classificati con tre diverse etichette (i colori)
Quando dobbiamo assegnare l’etichetta (ossia il colore) a un nuovo esemplare, possiamo scegliere quella dei suoi k punti più vicini.
- Comiciamo considerando k = 1. Riferendoci alla Figura 2, proviamo a etichettare il nuovo esemplare rappresentato dalla croce: ha come punto più vicino un punto azzurro, dunque gli assegniamo colore azzurro.
Figura 2: classificazione del nuovo punto come azzurro con k = 1
Se consideriamo invece la situazione illustrata nella Figura 3, etichettiamo il nuovo punto come arancione, perché tale è il suo punto più vicino.
Figura 3: classificazione del nuovo punto come arancione con k = 1
- Passiamo ora a considerare k = 3. La Figura 4 mostra la stessa situazione della Figura 2, ma ora non dobbiamo considerare il punto più vicino, bensì i tre punti più vicini. Di essi, due sono arancioni e uno solo azzurro, quindi il nuovo punto va etichettato come arancione.
Figura 4: classificazione per k = 3.
Nell’algoritmo KNN ci sono due parametri da considerare: il valore di k e la metrica per il calcolo della distanza. Negli esempi proposti abbiamo calcolato la distanza euclidea.
Come abbiamo visto, k definisce quanti punti vicini verranno controllati per determinare la classificazione di un nuovo punto. La scelta di k dipende in gran parte dai dati di input: i dati con più valori anomali o rumore probabilmente funzioneranno meglio con valori più elevati di k, che smorza quindi l’impatto di possibili anomalie. Inoltre, l’uso di un valore di k dispari permette di evitare pareggi nella classificazione.
Infine, spesso si ricorre al confronto delle prestazioni dell’algoritmo KNN con diversi valori di k, per selezionare poi quello ottimale per lo specifico set di dati.
Laboratorio di machine learning con Python
In questo laboratorio realizzeremo un sistema di classificazione con l’algoritmo KNN in Python.
Python è un linguaggio di programmazione molto diffuso, grazie alla sua facilità di utilizzo e alla disponibilità di numerose librerie, tra cui quelle per l’intelligenza artificiale, come scikit-learn.
Prima di proseguire, svolgiamo alcune operazioni preliminari necessarie:
Figura 6: installazione dell'estensione per Python di Visual Studio Code
Una volta installata la libreria, possiamo importarla nel programma Python e utilizzarne le funzionalità aggiungendo all’inizio del file la seguente riga:
Di questa libreria sfrutteremo diversi componenti, tra cui il dataset iris: si tratta di un dataset famoso e usatissimo che classifica i fiori iris.
I 150 esemplari nel dataset iris hanno 4 feature:
e sono suddivisi in tre classi, 50 esemplari per ciascuna classe:
La seguente tabella contiene alcuni dati del dataset. Quello che faremo è dividerli verticalmente per separare le feature dalle label e orizzontalmente per dividere il training set, che conterrà l’80% degli esemplari, dal test set, con il restante 20%.
Avremo quindi:
Usiamo convenzionalmente lettere maiuscole per designare matrici (X_train e X_test) e minuscole per i vettori (y_train e y_test).
La prima operazione da effettuare è caricare il dataset dalla libreria:
In seguito, dobbiamo separare le feature dalle label (dette anche target).
Per stampare una descrizione del risultato, possiamo usare:
L’output ottenuto è il seguente:
e indica che la matrice delle feature ha 150 righe e 4 colonne, mentre il vettore dei target ha 150 righe.
Successivamente, separiamo il training set dal test set con la funzione train_test_split()
Questa funzione riceve come parametri la matrice delle feature X e il vettore dei target y, oltre alla dimensione del test set (20%). Restituisce le 4 porzioni della matrice originale, che possiamo descrivere con la seguente stampa:
L’output è il seguente:
e indica che, come previsto, le porzioni del training set hanno 120 righe, che corrisponde all’80% del dataset originale, e quelle del test set contengono le rimanenti 30, pari al 20%.
Poiché vogliamo utilizzare l’algoritmo KNN, creiamo il corrispondente modello specificando che devono essere usati tre vicini per la classificazione, da pesare uniformemente:
Passiamo poi ad addestrare il modello con i dati del training set:
Con il modello addestrato, prediciamo le label per i dati del test set:
e infine valutiamo la bontà delle predizioni ottenute calcolando tre misure della bontà del risultato:
L’accuracy misura la percentuale di casi correttamente classificati rispetto al totale dei casi, la precision il numero di casi correttamente classificati come positivi rispetto al totale dei positivi predetti e la recall il numero di casi correttamente classificati come positivi rispetto al totale dei casi positivi.
Notiamo che per precision e recall vengono fornite tre misure distinte, una per ogni classe.
Python è un linguaggio di programmazione molto diffuso, grazie alla sua facilità di utilizzo e alla disponibilità di numerose librerie, tra cui quelle per l’intelligenza artificiale, come scikit-learn.
Prima di proseguire, svolgiamo alcune operazioni preliminari necessarie:
- installare Python: occorre scaricare il programma di installazione dal sito ufficiale: https://www.python.org/downloads
Una volta lanciato il programma di installazione, assicurarsi di selezionare Add python.exe to PATH prima di premere Install Now. - scegliere un ambiente di sviluppo (IDE, Integrated Development Environment). Tra i tanti, Visual Studio Code permette di scrivere codice in moltissimi linguaggi di programmazione. Per sviluppare programmi in Python, è necessario installare l’apposita estensione: selezionare il pulsante Estensioni nella barra sulla sinistra e scrivere Python nella barra di ricerca.
Figura 6: installazione dell'estensione per Python di Visual Studio Code
- installare la libreria scikit-learn: in questo laboratorio ci servirà la libreria scikit-learn, che dobbiamo però preventivamente installare. Possiamo farlo con il gestore di pacchetti predefinito in Python, chiamato pip. Apriamo la PowerShell di Windows e scriviamo:
pip install scikit-learn
Una volta installata la libreria, possiamo importarla nel programma Python e utilizzarne le funzionalità aggiungendo all’inizio del file la seguente riga:
import sklearn
Di questa libreria sfrutteremo diversi componenti, tra cui il dataset iris: si tratta di un dataset famoso e usatissimo che classifica i fiori iris.
I 150 esemplari nel dataset iris hanno 4 feature:
- lunghezza del sepalo
- larghezza del sepalo
- lunghezza del petalo
- larghezza del petalo
e sono suddivisi in tre classi, 50 esemplari per ciascuna classe:
- iris-setosa
- iris-versicolour
- iris-virginica
La seguente tabella contiene alcuni dati del dataset. Quello che faremo è dividerli verticalmente per separare le feature dalle label e orizzontalmente per dividere il training set, che conterrà l’80% degli esemplari, dal test set, con il restante 20%.
Avremo quindi:
- X_train: matrice delle feature del training set
- y_train: vettore delle label del training set
- X_test: matrice delle feature del test set
- y_test: vettore delle label del test set
Usiamo convenzionalmente lettere maiuscole per designare matrici (X_train e X_test) e minuscole per i vettori (y_train e y_test).
La prima operazione da effettuare è caricare il dataset dalla libreria:
iris = datasets.load_iris()
In seguito, dobbiamo separare le feature dalle label (dette anche target).
X = iris.data
y = iris.target
Per stampare una descrizione del risultato, possiamo usare:
print("Features:", X.shape)
print("Targets:", y.shape)
L’output ottenuto è il seguente:
Features: (150, 4)
Targets: (150,)
e indica che la matrice delle feature ha 150 righe e 4 colonne, mentre il vettore dei target ha 150 righe.
Successivamente, separiamo il training set dal test set con la funzione train_test_split()
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)
Questa funzione riceve come parametri la matrice delle feature X e il vettore dei target y, oltre alla dimensione del test set (20%). Restituisce le 4 porzioni della matrice originale, che possiamo descrivere con la seguente stampa:
print("Features (training):", X_train.shape)
print("Features (testing):", X_test.shape)
print("Targets (training):",y_train.shape)
print("Targets (testing):",y_test.shape)
L’output è il seguente:
Features (training): (120, 4)
Features (testing): (30, 4)
Targets (training): (120,)
Targets (testing): (30,)
e indica che, come previsto, le porzioni del training set hanno 120 righe, che corrisponde all’80% del dataset originale, e quelle del test set contengono le rimanenti 30, pari al 20%.
Poiché vogliamo utilizzare l’algoritmo KNN, creiamo il corrispondente modello specificando che devono essere usati tre vicini per la classificazione, da pesare uniformemente:
knn = neighbors.KNeighborsClassifier(n_neighbors=3, weights='uniform')
Passiamo poi ad addestrare il modello con i dati del training set:
knn.fit(X_train, y_train)
Con il modello addestrato, prediciamo le label per i dati del test set:
prediction = knn.predict(X_test)
e infine valutiamo la bontà delle predizioni ottenute calcolando tre misure della bontà del risultato:
accuracy = metrics.accuracy_score(y_test, prediction)
precision = metrics.precision_score(y_test, prediction, average=None)
recall = metrics.recall_score(y_test, prediction, average=None)
L’accuracy misura la percentuale di casi correttamente classificati rispetto al totale dei casi, la precision il numero di casi correttamente classificati come positivi rispetto al totale dei positivi predetti e la recall il numero di casi correttamente classificati come positivi rispetto al totale dei casi positivi.
Notiamo che per precision e recall vengono fornite tre misure distinte, una per ogni classe.
Conclusioni
Il machine learning è una branca dell'intelligenza artificiale che si occupa di sviluppare algoritmi che apprendono dai dati ed effettuano previsioni o prendono decisioni sulla base di quanto appreso.
Esistono diverse tecniche di machine learning: l’apprendimento supervisionato, non supervisionato, per rinforzo. La classificazione è un tipo di apprendimento supervisionato e consiste nell’assegnare una classe a un insieme di dati in base alle loro caratteristiche e serve a organizzare i dati in gruppi predefiniti in base alle loro caratteristiche. L’algoritmo KNN è un semplice algoritmo di classificazione che assegna a un esemplare l’etichetta prevalente nei k esemplari più vicini.
Uno dei linguaggi più utilizzati nel campo dell’intelligenza artificiale è Python anche grazie alla disponibilità di diverse librerie pronte all’uso, come scikit-learn. Grazie a questa libreria, la realizzazione e la valutazione di un classificatore che utilizzi l’algoritmo KNN è semplice e veloce.
Esistono diverse tecniche di machine learning: l’apprendimento supervisionato, non supervisionato, per rinforzo. La classificazione è un tipo di apprendimento supervisionato e consiste nell’assegnare una classe a un insieme di dati in base alle loro caratteristiche e serve a organizzare i dati in gruppi predefiniti in base alle loro caratteristiche. L’algoritmo KNN è un semplice algoritmo di classificazione che assegna a un esemplare l’etichetta prevalente nei k esemplari più vicini.
Uno dei linguaggi più utilizzati nel campo dell’intelligenza artificiale è Python anche grazie alla disponibilità di diverse librerie pronte all’uso, come scikit-learn. Grazie a questa libreria, la realizzazione e la valutazione di un classificatore che utilizzi l’algoritmo KNN è semplice e veloce.
Riferimenti
Stuart J. Russell, Peter Norvig, Artificial Intelligence: a modern approach (4th edition), Pearson 2020
Python language https://www.python.org/
Scikit-learn https://scikit-learn.org/stable/
Python language https://www.python.org/
Scikit-learn https://scikit-learn.org/stable/