TD 06

SVM

Exercice 1.

N.B. : Ce premier exemple est une adaptation de l'excellent support de cours disponible à l'adresse :

eric.univ-lyon2.fr/~ricco/tanagra/fichiers/fr_Tanagra_SVM_R_Python.pdf

In [23]:
import numpy as np
import pandas as pa
import matplotlib.pyplot as plt
from random import random
import warnings
warnings.filterwarnings("ignore")
In [24]:
def myscatter(df, dfpos, dfneg):
    plt.scatter(df.iloc[:,0], df.iloc[:,1], color='white')
    for i in dfpos.index:
        plt.annotate(i, xy=(df.loc[i,'X1'], df.loc[i,'X2']), xytext=(-3,-3), 
                     textcoords='offset points', color='red')
    for i in dfneg.index:
        plt.annotate(i, xy=(df.loc[i,'X1'], df.loc[i,'X2']), xytext=(-3,-3), 
                     textcoords='offset points', color='blue')        
In [25]:
dic = {'X1': [1, 2, 4, 6, 8, 5, 7, 9, 12, 13],
      'X2': [3, 1, 5, 9, 7, 1, 1, 4, 7, 6],
      'y': [-1, -1, -1, -1, -1, 1, 1, 1, 1, 1]}
df = pa.DataFrame(data=dic)
df
Out[25]:
X1 X2 y
0 1 3 -1
1 2 1 -1
2 4 5 -1
3 6 9 -1
4 8 7 -1
5 5 1 1
6 7 1 1
7 9 4 1
8 12 7 1
9 13 6 1
In [26]:
df.head()
print(df.values.shape)
print(df.values[:,0:2].shape)
print(df.values[:,2].shape)
(10, 3)
(10, 2)
(10,)
In [27]:
dfpos = df[df.y==1]
dfneg = df[df.y==-1]
In [28]:
myscatter(df, dfpos, dfneg)
plt.show()
In [27]:
from sklearn.svm import SVC
svm = SVC(kernel='linear')
svm.fit(df.values[:,0:2], df.values[:,2])
Out[27]:
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
    decision_function_shape='ovr', degree=3, gamma='auto_deprecated',
    kernel='linear', max_iter=-1, probability=False, random_state=None,
    shrinking=True, tol=0.001, verbose=False)
In [28]:
print(svm.support_.shape)
(3,)
In [29]:
print(df.index[svm.support_])
Int64Index([1, 4, 5], dtype='int64')
In [31]:
print(svm.dual_coef_)
[[-0.33325096 -0.11109464  0.44434559]]
In [33]:
print(svm.support_vectors_)
[[2. 1.]
 [8. 7.]
 [5. 1.]]
In [36]:
abs = svm.support_vectors_[:,0]
ord = svm.support_vectors_[:,1]
myscatter(df, dfpos, dfneg)
plt.scatter(abs, ord, marker="s", s=200, facecolors='none', edgecolors='black')
plt.show()
In [38]:
print(svm.coef_)
[[ 0.66646897 -0.66656782]]
In [39]:
print(svm.intercept_)
[-1.66597472]
In [41]:
xf = np.array([3, 12])
yf = -svm.coef_[0][0]/svm.coef_[0][1] * xf - svm.intercept_/svm.coef_[0][1]
xb = np.array([4.5, 12])
yb = -svm.coef_[0][0]/svm.coef_[0][1] * xb - (svm.intercept_ - 1.)/svm.coef_[0][1]
xh = np.array([2, 11])
yh = -svm.coef_[0][0]/svm.coef_[0][1] * xh - (svm.intercept_ + 1.)/svm.coef_[0][1]
In [42]:
myscatter(df, dfpos, dfneg)
plt.scatter(abs, ord, marker="s", s=200, facecolors='none', edgecolors='black')
plt.plot(xf, yf, c='green')
plt.plot(xb, yb, c='gray')
plt.plot(xh, yh, c='gray')
plt.show()

SVM non linéaire, kernel trick

Danns cet exercice, on s'intéresse à l'utilisation des techniques de noyau pour séparer des données non linéairement séparables. Nous allons travailler avec le dataset iris déjà vu dans les anciens tds.

Pour rappel (voir le cours), l'utilisation des noyaux permet de changer de dimension et de rendre les données linéairement séparables. Voici trois fonctions noyau très utiles :

  • linéaire : $<x, x'>$

  • polynomial : $(\gamma<x, x'> + r)^d$

  • rbf : $exp(−\gamma(\mid\mid x − x'\mid\mid)^2)$.

In [29]:
#On commence par importer les modules nécessaire :
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
from sklearn import svm
In [30]:
#Puis on charge les données 
from sklearn import datasets
iris = datasets.load_iris()

# On se focalise juste sur les deux premiers descripteurs et bien sûr la classe 
X = iris.data[:, :2]
y = iris.target
In [31]:
#La fonction suivante permet de créer un maillage pour y représenter le nuage de points, les frontières etc
def make_meshgrid(x, y, h=.02):
    """Create a mesh of points to plot in

    Parameters
    ----------
    x: data to base x-axis meshgrid on
    y: data to base y-axis meshgrid on
    h: stepsize for meshgrid, optional

    Returns
    -------
    xx, yy : ndarray
    """
    x_min, x_max = x.min() - 1, x.max() + 1
    y_min, y_max = y.min() - 1, y.max() + 1
    xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
                         np.arange(y_min, y_max, h))
    return xx, yy
In [32]:
#On utilisera la fonction suivante pour dessiner le nuage de points et les frontières trouvées par le calssifieur
def plot_contours(ax, clf, xx, yy, **params):
    """Plot the decision boundaries for a classifier.

    Parameters
    ----------
    ax: matplotlib axes object
    clf: a classifier
    xx: meshgrid ndarray
    yy: meshgrid ndarray
    params: dictionary of params to pass to contourf, optional
    """
    Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
    Z = Z.reshape(xx.shape)
    out = ax.contourf(xx, yy, Z, **params)
    return out
In [33]:
# On instancie plusieurs modèles avec différents paramètres et différentes fonction de noyau. On les entraîne 
# ensuite sur nos données
C = 1.0  # SVM regularization parameter
models = (svm.SVC(kernel='linear', C=C),
          svm.LinearSVC(C=C, max_iter=10000),
          svm.SVC(kernel='rbf', gamma=0.7, C=C),
          svm.SVC(kernel='poly', degree=3, gamma='auto', C=C))
models = (clf.fit(X, y) for clf in models)
In [34]:
# Cette cellule donne le code permettant de dessiner les frontières trouvées par les différents modèles

# Titres des figures :
titles = ('SVC with linear kernel',
          'LinearSVC (linear kernel)',
          'SVC with RBF kernel',
          'SVC with polynomial (degree 3) kernel')

# Une grille 2x2 pour dessiner :
fig, sub = plt.subplots(2, 2)
plt.subplots_adjust(wspace=0.4, hspace=0.4)

X0, X1 = X[:, 0], X[:, 1]
xx, yy = make_meshgrid(X0, X1)

for clf, title, ax in zip(models, titles, sub.flatten()):
    plot_contours(ax, clf, xx, yy,
                  cmap=plt.cm.coolwarm, alpha=0.8)
    ax.scatter(X0, X1, c=y, cmap=plt.cm.coolwarm, s=20, edgecolors='k')
    ax.set_xlim(xx.min(), xx.max())
    ax.set_ylim(yy.min(), yy.max())
    ax.set_xlabel('Sepal length')
    ax.set_ylabel('Sepal width')
    ax.set_xticks(())
    ax.set_yticks(())
    ax.set_title(title)

plt.show()
In [ ]: