Cette page fait partie du cours de polytech PeiP1 et 2 Bio
10. Mise en pratique : SVM
10.1. Introduction
Les SVM (Support Vector Machines) où Machines à Vecteur de Support sont en fait un classifieur
linéaire dit à large marge.
On rappelle que le classifieur permet de séparer (classer) des données lorsque l'on connaît
déjà les classes existantes. On parle alors de classification Supervisée par opposition
à la classification Non Supervisée pour laquelle on ne connaît pas le nombre de classes.
- classification Supervisée : on connaît le nombre de classes
- classification Non Supervisée : on ne connaît pas le nombre de classes
10.2. Le cadre théorique
Voici deux liens concernant des éléments théoriques liés aux SVM :
L'utilisation d'un kernel (qui est une fonction) permet de modifier l'espace initial
des données et de les transposer dans un espace d'ordre supérieur :
SVM Linéaire sans Kernel
SVM Linéaire avec Kernel $x^2$
Le problème des SVM et qu'elles dépendent de beaucoup de paramètres et que la recherche
des meilleurs paramètres (ceux qui donnent la meilleure prédiction) peut demander beaucoup
de temps. On pourra, afin de les rechercher, utiliser la classe
GridSearchCV
du paquet sklearn.model_selection.
10.3. Application aux Iris de Fisher
10.3.1. Apprentissage et validation
On essaye d'appliquer le classifieur SVM aux iris de Fisher
afin de prédire, à partir des données des sépales ou pétales, à quelle espèce appartient l'iris :
Setosa, Versicolor, Virginica .
Dans le cadre de l'apprentissage, on a tendance à séparer les données en
deux sous-ensembles :
- l'ensemble d'apprentissage $(X_a, y_a)$ qui permet de calculer une SVM
- l'ensemble de validation $(X_v, y_v)$
On se trouve confronté ici à un dilemme du même type que celui ci:
- soit on utilise cette technique de séparation des données en sous-ensembles
d'apprentissage et de validation, mais on risque de sous-apprendre par
rapport à l'ensemble des données, c'est à dire de ne pas prendre en compte des
données essentielles à l'apprentissage
- soit on prend toutes les données et on risque de nous reprocher d'avoir une
connaissance parfaite de nos données, ce que l'on peut qualifier de sur
apprentissage
Tout ceci n'est qu'une affaire de point de vue car dans le cas où on prend la
totalité des données, il est évident que de nouvelles données viendront s'ajouter
par la suite qui confirmeront ou infirmeront le modèle d'apprentissage.
10.3.2. Résolution
Pour résoudre notre problèmen on utilise la classe SVC (C-Support Vector Classification) du paquet svm.
svm_iris.py
#####################################################################
# Exemple d'utilisation de SVM
# Utilisation des données des iris de Fisher
#####################################################################
#####################################################################
# import des librairies
#####################################################################
from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.svm import SVC
from sklearn.metrics import accuracy_score
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import pandas as pd
import numpy as np
import sys
#
# Définition de chaines pour l'affichage
#
line = "=" * 50
separator = "\n" * 2
#####################################################################
# Données
#####################################################################
#
# On charge les données depuis sklearn
# On obtient un sklearn.utils.Bunch
#
iris = load_iris()
#
# Affiche les différents champs
#
iris_keys = iris.keys()
for k in iris_keys:
print(line)
print(k)
print(iris[k])
#
# On transforme les données en DataFrame de pandas
# afin de pouvoir les manipuler plus simplement
#
df = pd.DataFrame(data = np.c_[ iris['data'], iris['target'] ],
columns= iris['feature_names'] + ['target'])
#
# On renomme les colonnes pour les manipuler plus
# simplement
# (inPlace=True évite de faire une copie du DataFrame)
#
df.rename( columns = {
'sepal length (cm)': 'sepal_length' ,
'sepal width (cm)': 'sepal_width',
'petal length (cm)': 'petal_length',
'petal width (cm)': 'petal_width'},
inplace=True )
#
# On garde toutes les propriétés sauf la cible pour effectuer
# le calcul de la SVM
#
variables_du_modele = df.columns.drop(['target'])
#
# y est le vecteur de sortie à prédire
#
y = df.target
#
# X est une matrice des données en entrées
#
X = df[ variables_du_modele ]
#####################################################################
# Séparation des données
# - données d'apprentissage X_a, y_a
# - données de validation X_v, y_v
#####################################################################
#
# On crée deux jeux de données à partir de (X,y)
# - le jeu d'apprentissage X_a, y_a (70% des individus)
# - le jeu de test (X_v, y_v) qui permettra de vérifier
# la prédiction (30% des individus)
#
X_a, X_v, y_a, y_v = train_test_split(X, y, test_size=0.30)
#####################################################################
# Classifieur
#####################################################################
#
# création du classifieur
#
classifier = SVC(C=0.05, kernel='linear', gamma='auto')
#
# calcul sur ensemble d'apprentissage
#
print(line)
print(" Classification sur ensemble d'apprentissage")
print(line)
classifier.fit(X_a, y_a)
#####################################################################
# Prédiction
# sur le jeu de validation
#####################################################################
print(line)
print("Prédiction")
print(line)
y_v_prime = classifier.predict(X_v)
print("précision=", accuracy_score(y_v, y_v_prime) )
print( str(classifier) )
#####################################################################
# graphique des données
#####################################################################
#
# On travaille à présent sur toutes les données et on compare
# la prédiction
#
y_prime = classifier.predict(X)
fig = plt.figure()
axes = fig.add_subplot(111, projection='3d')
plt.title("Résultats Classification SVM")
axe1 = X['sepal_length']
axe2 = X['sepal_width']
axes.scatter(axe1, axe2, y.tolist(), c=y_prime, cmap=plt.cm.jet)
plt.show()
Exercice 10.1
Tester la solution précédente avec d'autres kernels comme :
classifier = SVC(C=0.006, kernel='rbf', gamma='scale')
ou
classifier = SVC(C=1.0, kernel='poly', gamma='auto', degree=7)
Qu'obtient-on comme résultat ?
10.4. Mise en application
Exercice 10.2
Utiliser le jeu de données breast_cancer de Scikit-Learn et tenter de créer une
SVM qui permet de différencier tumeurs malignes des tumeurs bénignes.