Definizione e comparazione dei modelli di classificazione con Scikit-Learn
SVM
1. Università degli Studi di Siena
Facoltà di Ingegneria Informatica
A.A. 2007 / 2008
Sistemi per il supporto
alle decisioni 2
Utilizzo delle Support Vector Machine per
determinare la tipologia dei vini
Prof. Marco Gori
Progetto realizzato da:
Panti Fabrizio
2. Introduzione:
Il progetto su cui ho lavorato è un problema di classificazione multiclasse. Il dataset utilizzato si
chiama WINE ed è scaricabile dal link http://archive.ics.uci.edu/ml/datasets/Wine
Si tratta di classificare in 3 categorie un insieme di 178 pattern, ciascuno caratterizzato da 13
attributi: Alcool, Acido malico, Cenere, Alcalinità della cenere, Magnesio, Totale fenoli,
Flavonoidi, Fenoli non flavonoidi, Proantocianine, Intensità del colore, Hue (luminosità),
OD280/OD315 di vini diluiti (densità ottica, espressa come rapporto tra lunghezze d’onda), Prolina.
Questi dati sono il risultato di una analisi chimica dei vini coltivati in Italia ma provenienti da tre
diverse coltivazioni. L’analisi ha determinato che ciascuno dei 3 tipi di vino è costituito da queste
13 caratteristiche significative. Il mio progetto consiste nell’utilizzare le Support Vector Machine
per classificare i 178 pattern del dataset in 3 classi, sulla base dei valori delle 13 features fornite
dall’analisi chimica.
Il progetto:
Per risolvere il problema di classificazione utilizzo il tool LibSVM versione 2.86 (riferimenti al
link http://www.csie.ntu.edu.tw/~cjlin/libsvm/ ). Il file dei dati usato è reperibile all’indirizzo
http://www.csie.ntu.edu.tw/~cjlin/libsvmtools/datasets/multiclass/wine.scale
e, per ragioni di stabilità numerica, lavoro su dati normalizzati nell’intervallo tra -1 e +1.
Non avendo due dataset distinti per il training ed il test, utilizzo l’unico dataset che ho a
disposizione con la tecnica della cross validation. Avendo 178 pattern, una buona scelta può essere
la 10-fold cross validation (160 pattern utilizzati per l’addestramento e 18 per il test), la 20-fold
(169 per il training e 9 per il test) oppure la leave one out (solo un pattern per il test, training
effettuato sugli altri 177), ciascuna tecnica iterata rispettivamente 10, 20 e 178 volte su dati distinti
e facendo la media dei risultati ottenuti in ciascuna iterazione.
Provo vari tipi di kernel: lineare, polinomiale, gaussiano, sigmoidale, commentando le differenze tra
essi e quale risulterà preferibile.
Utilizzo l’istruzione svm-train; la sintassi da seguire è la seguente: svm-train [opzioni]
nome_del_file
opzioni:
-t tipo di funzione kernel:
0 kernel lineare
1 kernel polinomiale
2 kernel gaussiano
3 kernel sigmoidale
-g parametro sigma del kernel gaussiano
-v numero di fold della cross validation
-c costo, è il parametro C della SVM, relativo al numero di errori di classificazione tollerati
Inizio ad esaminare il comportamento di un kernel lineare; veloce da calcolare e senza bisogno di
settare dei parametri addizionali. Scrivo svm-train –t 0 –v 10 –c 2 wine.scale.txt
Ottengo un totale di 27 support vector ed un’accuratezza del 96% utilizzando la 10-fold cross
validation.
Total nSV = 27
Cross Validation Accuracy = 96.0674%
2
3. Provo una cross validation 20-fold, sempre utilizzando un kernel lineare:
svm-train –t 0 –v 20 –c 2 wine.scale.txt
Noto che l’accuratezza sale al 96,6% con 28 support vector
Total nSV = 28
Cross Validation Accuracy = 96.6292%
Con la leave one out ( –v 178 ) ottengo risultati identici
Total nSV = 28
Cross Validation Accuracy = 96.6292%
Concludo asserendo che un kernel lineare mi fornisce una buonissima classificazione in tempi di
elaborazione contenuti.
Passo adesso in rassegna un kernel polinomiale di grado 3; di seguito i risultati rispettivamente della
cross validation 10-fold, 20-fold, leave-o-o
Total nSV = 153
Cross Validation Accuracy = 45.5056%
Total nSV = 159
Cross Validation Accuracy = 47.191%
Total nSV = 167
Cross Validation Accuracy = 47.191%
Vedo che il kernel polinomiale non fa al mio scopo, sia per la bassa accuratezza ottenuta, sia per
l’elevato numero di support vector risultante. Infatti, col fatto che i support vector sono i dati più
significativi tra quelli in ingresso, quelli cioè in cui è concentrata tutta l’informazione del dataset,
conviene avere un numero di vettori di supporto basso. Concludo che è inutile alzare il grado della
funzione polinomiale per cercare di migliorare le cose, preferisco scartare questo tipo di kernel e
vedere il comportamento di uno gaussiano. Adesso è necessario anche specificare il valore sigma
relativo alla varianza, cioè quanto la campana è più o meno stretta. In genere si preferiscono valori
di sigma bassi, però non eccessivamente piccoli, altrimenti rischio di incorrere nel fenomeno
dell’overfitting, con conseguente perdita della capacità di generalizzazione del modello.
Provo la 10-fold cross validation con sigma=0,1 =0,15 =0,20 rispettivamente
Total nSV = 53
Cross Validation Accuracy = 98.8764%
Total nSV = 49
Cross Validation Accuracy = 98.8764%
Total nSV = 52
Cross Validation Accuracy = 98.3146%
Ed ho ottenuto dei risultati di tutto rispetto. Provo la 20-fold, sempre con sigma=0,1 =0,15 =0,20
rispettivamente
3
4. Total nSV = 55
Cross Validation Accuracy = 98.8764%
Total nSV = 50
Cross Validation Accuracy = 99.4382%
Total nSV = 51
Cross Validation Accuracy = 98.8764%
Ed infine provo la leave one out, sempre con i medesimi parametri
Total nSV = 58
Cross Validation Accuracy = 99.4382%
Total nSV = 52
Cross Validation Accuracy = 99.4382%
Total nSV = 52
Cross Validation Accuracy = 98.8764%
Noto che il kernel gaussiano con spread 0,15 è l’ideale al caso mio: sia nella 20-fold cross
validation sia nella l-o-o fornisce un’accuratezza del 99,4382%, la più alta raggiunta finora.
Avevo già accennato che un sigma troppo piccolo rischia di farmi incorrere nel fenomeno
dell’overfitting (troppi support vector, perdita in capacità di generalizzazione); voglio vedere se è
vero, impostando ad esempio un sigma = 0,025. I seguenti sono i risultati della 20-fold e della l-o-o:
Total nSV = 85
Cross Validation Accuracy = 97.7528%
Total nSV = 91
Cross Validation Accuracy = 97.191%
Vedo che, oltre ad aver perso in accuratezza, circa la metà dei dati del training set sono diventati
vettori di supporto!
In ultima analisi passo in rassegna un kernel di tipo sigmoidale; di seguito i risultati rispettivamente
della cross validation 10 fold, 20 fold, leave one out.
Total nSV = 65
Cross Validation Accuracy = 98.3146%
Total nSV = 70
Cross Validation Accuracy = 98.3146%
Total nSV = 72
Cross Validation Accuracy = 98.3146%
Noto che, per quanto di tutto rispetto, i risultati ottenuti sono peggiori rispetto a quelli forniti da una
funzione kernel gaussiana.
Concludo affermando che il kernel gaussiano è quello preferibile nel mio problema di
classificazione, dato che mi fornisce un’elevatissima accuratezza ed un ragionevole numero di
vettori di supporto. Anche il kernel lineare è da tenere in considerazione, dato che è quello che ha
4
5. fornito il minor numero di vettori di supporto. Col fatto che essi concentrano in sé tutta
l’informazione del dataset (pattern che non sono vettori di supporto danno contributo nullo nella
classificazione), avere un basso numero di vettori di supporto è un buon compromesso con
un’accuratezza che, seppur più bassa rispetto a quella del caso gaussiano, è pur sempre molto
buona.
Il tool LibSVM fornisce anche un’interfaccia grafica denominata svm-toy, utile per plottare i dati
in ingresso e valutare così i risultati ottenuti dai vari tipi di kernel.
svm-toy lavora esclusivamente su dati normalizzati nell’intervallo [0 , +1]; col fatto che i miei dati
appartengono all’intervallo [-1 , +1] è opportuno traslarli e scalarli. La cosa più semplice da fare è
sommare il valore 1 a ciascuna componente dell’ingresso e dividere il risultato per 2.
Per fare la normalizzazione esiste l’istruzione svm-scale
Usage: svm-scale [options] data_filename
options:
-l lower : x scaling lower limit (default -1)
-u upper : x scaling upper limit (default +1)
Mi serve come lower-bound il valore 0 (-l 0) e come upper-bound 1 (-u 1), inoltre ho bisogno di
salvare i risultati per poterli poi utilizzare con l’interfaccia grafica (conviene quindi buttarli in un
file di testo con la direttiva > nome_del_nuovo_file), scriverò cioè l’istruzione
svm-scale –l 0 –u 1 wine.scale.txt > winescale01.txt
Adesso il file winescale01.txt conterrà i dati normalizzati tra 0 e 1
Lancio l’interfaccia grafica con l’istruzione svm-toy e carico il file winescale01.txt appena creato
Sono stati plottati tutti i punti del dataset, con 3 colori differenti a seconda della categoria di
appartenenza. Il compito del mio classificatore è di dividere lo spazio delle feature (cioè tutta la
finestra nera) in zone di 3 colori differenti di modo che ulteriori dati in ingresso, di cui non conosco
5
6. a priori la classe, saranno attribuiti ad una certa categoria in base alla superficie di separazione
calcolata dalla funzione kernel.
Utilizzo l’interfaccia grafica con istruzioni identiche a quelle che avevo fornito da linea di comando
alla svm-train. Provo quindi il kernel gaussiano con varianza 0,15 e 20-fold cross validation, quello
cioè che avevo visto risultare ottimale, e lancio la simulazione
Noto che ci sono alcuni punti non correttamente classificati, ma il risultato complessivo è da
considerarsi buono. Se volessi tollerare un numero di errori diverso basterà variare il valore del
parametro C, ottenendo una superficie di separazione leggermente differente.
6