import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
digits = datasets.load_digits()
X = digits.data
y = digits.target
print(X[1])
print(X[1].reshape(8,8))
plt.figure()
plt.imshow(X[1].reshape(8,8),cmap=plt.cm.gray_r)
plt.show()
for i in range(0,10):
print('Chiffre',i,':', sum(y==i))
Les classes sont à peu près équilibrées.
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X,y,train_size=200)
from sklearn.neighbors import KNeighborsClassifier
from sklearn.model_selection import cross_val_score
knn = KNeighborsClassifier(n_neighbors=5)
scores = cross_val_score(knn, X_train, y_train, cv=7)
print(scores)
scores
contient les scores de validation pour chacun des 7 couples d'échantillons apprentissage/validation considérés par la 7-CV. Le score final de la 7-CV est donc la moyenne de ces 7 scores.
print("Score de validation de la 7-CV de l'algorithme 5NN: ", np.mean(scores))
from sklearn.model_selection import validation_curve
k_range = range(1,21)
train_scores, valid_scores = validation_curve(KNeighborsClassifier(),
X_train,
y_train,
param_name="n_neighbors",
param_range=k_range,
cv=7)
train_mean_score = np.mean(train_scores,axis=1)
valid_mean_score = np.mean(valid_scores,axis=1)
plt.plot(k_range, train_mean_score, label='Score d\'apprentissage')
plt.plot(k_range, valid_mean_score, label='Score de validation')
plt.xlabel("Hyperparamètre k")
plt.ylabel("Score 7-CV")
plt.legend()
plt.show()
k_best = k_range[np.argmax(valid_mean_score)]
Pour les grandes valeurs de k considérées, on voit que les scores d'apprentissage et de validation décroissent toutes les deux lorsque k croît. De plus, on sait que le biais de l'algorithme kNN augmente lorsque k croît. On en déduit qu'il y a sous-apprentissage (underfitting) pour les grandes valeurs de k. Il est donc inutile de considérer des valeurs k encore plus grandes.
from sklearn.model_selection import learning_curve
train_size_range = range(10,151,5)
train_sizes, train_scores, valid_scores = learning_curve(
KNeighborsClassifier(n_neighbors=k_best),
X_train,y_train,train_sizes=train_size_range,
cv=7)
train_mean_score = np.mean(train_scores,axis=1)
valid_mean_score = np.mean(valid_scores,axis=1)
plt.plot(train_sizes, train_mean_score, label='Score d\'apprentissage')
plt.plot(train_sizes, valid_mean_score, label='Score de validation')
plt.xlabel("Taille de l'échanillon d'apprentissage")
plt.ylabel("Score 7-CV")
plt.legend()
plt.show()
On voit que la courbe de score de validation atteint ici un plateau (les résultats peuvent varier). Il est donc inutile de considérer des échantillons d'apprentissage plus grands.
import numpy as np
knn_dict = {}
score_train = []
score_valid = []
for size in train_size_range:
X_train_,X_valid_,y_train_,y_valid_ = train_test_split(X_train,y_train,train_size=size)
knn_dict[size] = KNeighborsClassifier(n_neighbors=k_best).fit(X_train_,y_train_)
score_train.append(knn_dict[size].score(X_train_,y_train_))
score_valid.append(knn_dict[size].score(X_valid_,y_valid_))
plt.plot(train_size_range, score_train, label='Score d\'apprentissage')
plt.plot(train_size_range, score_valid, label='Score de validation')
plt.xlabel("Taille de l'échantillon d'apprentissage")
plt.ylabel("Score")
plt.legend()
plt.show()
Le score de la validation croisée est obtenue par la moyenne de plusieurs (ici 7) scores de validation simple. Elle présente donc beaucoup moins de fluctuations, et permet, ici pour la lecture des courbes d'apprentissage, de mieux saisir le comportement des courbes.
knn_best = KNeighborsClassifier(n_neighbors=k_best).fit(X_train,y_train)
print('Score de test:',knn_best.score(X_test,y_test))
import pandas as pd
pd.crosstab(y_test,knn_best.predict(X_test))
L'erreur la plus courante est ici le 8 qui est pris pour un 1 (les résultats peuvent varier).
def shift_image(image,direction):
dx, dy = direction
x_shifted_image = np.zeros((8,8))
if dx > 0:
x_shifted_image[:,dx:]=image[:,:-dx]
elif dx < 0:
x_shifted_image[:,:dx]=image[:,-dx:]
else:
x_shifted_image=image
xy_shifted_image = np.zeros((8,8))
if dy > 0:
xy_shifted_image[:-dy]=x_shifted_image[dy:]
elif dy < 0:
xy_shifted_image[-dy:]=x_shifted_image[:dy]
else:
xy_shifted_image=x_shifted_image
return xy_shifted_image
plt.figure()
plt.imshow(shift_image(X[1].reshape(8,8),np.array([-1,1])),cmap=plt.cm.gray_r)
plt.show()
plt.figure()
plt.imshow(shift_image(X[1].reshape(8,8),np.array([2,-1])),cmap=plt.cm.gray_r)
plt.show()
X_augmented = np.empty((0,64))
y_augmented = np.empty((0,1))
foo = [-1,0,1]
for dx in foo:
for dy in foo:
X_augmented = np.append(X_augmented,[shift_image(x.reshape(8,8),np.array([dx,dy])).reshape(64) for x in X],axis=0)
y_augmented = np.append(y_augmented,y)
X_augmented_train, X_augmented_test, y_augmented_train, y_augmented_test = train_test_split(X_augmented,y_augmented,train_size=400)
from sklearn.model_selection import validation_curve
k_range = range(1,21)
train_scores, valid_scores = validation_curve(KNeighborsClassifier(),
X_augmented_train,
y_augmented_train,
"n_neighbors",
k_range,
cv=7)
train_mean_score = np.mean(train_scores,axis=1)
valid_mean_score = np.mean(valid_scores,axis=1)
plt.plot(k_range, train_mean_score, label='Score d\'apprentissage')
plt.plot(k_range, valid_mean_score, label='Score de validation')
plt.xlabel("Hyperparamètre k")
plt.ylabel("Score 7-CV")
plt.legend()
plt.show()
k_best = k_range[np.argmax(valid_mean_score)]
train_size_range = range(10,251,10)
train_sizes, train_scores, valid_scores = learning_curve(
KNeighborsClassifier(n_neighbors=k_best),
X_augmented_train,y_augmented_train,train_sizes=train_size_range,
cv=7)
train_mean_score = np.mean(train_scores,axis=1)
valid_mean_score = np.mean(valid_scores,axis=1)
plt.plot(train_sizes, train_mean_score, label='Score d\'apprentissage')
plt.plot(train_sizes, valid_mean_score, label='Score de validation')
plt.xlabel("Taille de l'échanillon d'apprentissage")
plt.ylabel("Score 7-CV")
plt.legend()
plt.show()
Le score d'apprentissage reste très élevé. Le score de test est nettement inférieur, continue d'augmenter avec avec la taille de l'échantille d'apprentissage. On est donc en situation de sur-apprentissage (overfitting). Il serait intéressant d'augmenter la taille de l'échantillon d'apprentissage. Travaillons avec un échantillon d'apprentissage/validation de taille 15000.
X_augmented_train, X_augmented_test, y_augmented_train, y_augmented_test = train_test_split(X_augmented,y_augmented,train_size=15000)
train_size_range = range(1000,10001,1000)
train_sizes, train_scores, valid_scores = learning_curve(
KNeighborsClassifier(n_neighbors=k_best),
X_augmented_train,y_augmented_train,train_sizes=train_size_range,
cv=7)
train_mean_score = np.mean(train_scores,axis=1)
valid_mean_score = np.mean(valid_scores,axis=1)
plt.plot(train_sizes, train_mean_score, label='Score d\'apprentissage')
plt.plot(train_sizes, valid_mean_score, label='Score de validation')
plt.xlabel("Taille de l'échanillon d'apprentissage")
plt.ylabel("Score 7-CV")
plt.legend()
plt.show()
La courbe du score de test semble (presque) atteindre un plateau. Il semble donc que nous ayons un échantillon d'apprentissage/validation suffisamment grand. Cronstruisons à présent notre estimateur kNN sur l'ensemble de cet échantillon, et examions son score sur l'échantillon de test.
print('Score de test:',KNeighborsClassifier(n_neighbors=k_best).fit(X_augmented_train,y_augmented_train).score(X_augmented_test,y_augmented_test))
Le prédicteur obtenu est meilleur.