HiQPdf Evaluation 08/22/2020
logoept.jpg
TP2 Apprentissage automatique
Aïmèrou Ndiaye
Exercice 1
1. Rappeler la fonction coût du modèle de régression linéaire h (x)
MSE(x,h(theta)) = 1/m Somme(i=1 à m) (theta.T x(i) - y(i))^2
2. Rappeler les étapes de l’algorithme de descente de gradient
1. On choisit un vecteur theta initial
2. On calcule le gradient de la fonction coût
3. On calcule un nouveau vecteur theta grâce à la descente de gradient
4. On recommence le processus jusqu'à atteindre un vecteur optimal
3.
a. Ecrire une fonction permettant de caculer h (x) en fonction de theta0 et theta1
In [1]: from numpy import *
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.animation as animation
# Fonction hypothèse
def h(theta0, theta1, X):
h = []
for i in range(len(X)):
h_i = theta0 + (theta1*X[i])
h.append(h_i)
return h
# Fonction coût
def cost_function (theta0, theta1, X, Y):
global_cost = 0
for i in range (len(X)):
cost_i = ( (theta0 + (theta1*X[i])) - Y[i] ) * ( (theta0 + (theta1*X[i])) - Y[i] )
global_cost += cost_i
return (1/ (2 * len(X))) * global_cost
b. Ecrire une fonction qui permet de calculer la dérivée partielle des paramètres theta0 et theta1
In [2]: # Dérivées partielles
def derivees_partielles(ancien_theta0, ancien_theta1, X, Y):
derivee_theta0 = float(0)
derivee_theta1 = float(0)
M = len(X)
for i in range (0, M):
derivee_theta0 += float( ( ancien_theta0 + (ancien_theta1 * X[i]) ) - float (Y[i]) )
derivee_theta1 += float( ( ancien_theta0 + (ancien_theta1 * X[i]) ) - float (Y[i]) ) * float (X[i])
derivee_theta0 = (1/M) * derivee_theta0
derivee_theta1 = (1/M) * derivee_theta1
return [ derivee_theta0 , derivee_theta1 ]
c. Ecrire une fonction qui permet de calculer itérativement theta en fonction du learning rate
In [3]: def nouveaux_thetas ( ancien_theta0, ancien_theta1, alpha, X, Y ):
[ derivee_theta0 , derivee_theta1 ] = derivees_partielles (ancien_theta0 , ancien_theta1, X, Y )
nouvelle_theta0 = ancien_theta0 - ( alpha * derivee_theta0 )
nouvelle_theta1 = ancien_theta1 - ( alpha * derivee_theta1 )
cost = cost_function ( nouvelle_theta0, nouvelle_theta1, X, Y )
return [ nouvelle_theta0, nouvelle_theta1, cost ]
d. En s’appuyant sur ces dernières fonctions, implémenter la descente de gradient
In [4]: def gradient_descent(X, Y, alpha=0.001, nombre_iterations=1000):
COST_RECORDER = [] HiQPdf Evaluation 08/22/2020
initial_theta0 = 0
initial_theta1 = 0
tmp_theta0 = initial_theta0
tmp_theta1 = initial_theta1
for i in range ( nombre_iterations ):
[ nouvelle_theta0, nouvelle_theta1, cost ] = nouveaux_thetas ( tmp_theta0, tmp_theta1, alpha, X, Y )
tmp_theta0 = nouvelle_theta0
tmp_theta1 = nouvelle_theta1
COST_RECORDER.append(cost)
return [ tmp_theta0, tmp_theta1, COST_RECORDER ]
4. Tester sur des données de votre choix l’algorithme
In [5]: from sklearn import linear_model
import seaborn as sns
iris = sns.load_dataset("iris")
iris.head()
X = iris["petal_length"]
Y = iris["petal_width"]
In [6]: [final_theta0, final_theta1, COST_RECORDER] = gradient_descent(X, Y)
print(final_theta0, final_theta1)
0.002219752613072853 0.3352241244088225
In [7]: import numpy as np
x = np.linspace(0,10)
y = final_theta0 + final_theta1 * x
plt.scatter(X, Y)
plt.plot(x,y)
plt.xlabel("Petal length")
plt.ylabel("Petal width")
plt.title("Régression linéaire sur le jeu de données iris")
plt.show()
5. Afficher l’évolution du coût d’ereur global en fonction du nombre d’itérations
In [8]: xx = []; yy =[]
# dessiner l’avancer des differents de J(theta0 , theta1 )
for i in range (len(COST_RECORDER)):
xx. append (i)
yy. append ( COST_RECORDER [i])
axes = plt. axes ()
axes . grid ()
plt . xlabel ('Nombre d\' iterations ')
plt . ylabel ('Cout d\' erreur global ')
plt . plot (xx ,yy)
plt . show ()
Exercice 2
In [9]: # importation des modules
import numpy as np HiQPdf Evaluation 08/22/2020
import matplotlib . pyplot as plt
# generation des données
x = np. array ([1 , 2, 3, 4, 5])
y = np. array ([4 , 2, 1, 3, 7])
plt . scatter (x, y);
1. Tester et interpréter le script qui suit
In [10]: from sklearn . linear_model import LinearRegression
X = x[:, np. newaxis ]
model = LinearRegression() . fit(X, y)
yfit = model . predict (X)
plt . scatter (x, y)
plt . plot (x, yfit );
On effectue une régression linéaire sur notre jeu de données précédemment généré. On constate que le biais du modèle est assez élevé.
2.
In [11]: # Modèle polynomial
from sklearn . preprocessing import PolynomialFeatures
poly = PolynomialFeatures ( degree =2, include_bias = False )
X2 = poly . fit_transform (X)
print (X2)
model = LinearRegression (). fit(X2 , y)
yfit = model . predict (X2)
plt . scatter (x, y)
plt . plot (x, yfit );
[[ 1. 1.]
[ 2. 4.]
[ 3. 9.]
[ 4. 16.]
[ 5. 25.]]
a. Que représente X2 ?
X2 est une matrice qui rajoute une colonne correspondant au carré du vecteur X.
b. Est ce que le modèle polynomial est meilleur que le modèle linéaire de la question précédente ?
En terme de biais, le modèle polynomial est meilleur que le modèle linéaire mais il faudrait aussi tenir compte de la variance afin de le confirmer.
c. Comparez les résultats obtenus lorsque l’on utilise un polynome de degré 2, 3, 4, 5
HiQPdf Evaluation 08/22/2020
In [12]: from sklearn . preprocessing import PolynomialFeatures
poly1 = PolynomialFeatures ( degree =2, include_bias = False )
poly2 = PolynomialFeatures ( degree =3, include_bias = False )
poly3 = PolynomialFeatures ( degree =4, include_bias = False )
poly4 = PolynomialFeatures ( degree =5, include_bias = False )
X21 = poly1 . fit_transform (X)
X22 = poly2 . fit_transform (X)
X23 = poly3 . fit_transform (X)
X24 = poly4 . fit_transform (X)
model1 = LinearRegression (). fit(X21 , y)
model2 = LinearRegression (). fit(X22 , y)
model3 = LinearRegression (). fit(X23 , y)
model4 = LinearRegression (). fit(X24 , y)
print("Scores: ")
print(model1.score(X21,y))
print(model2.score(X22,y))
print(model3.score(X23,y))
print(model4.score(X24,y))
yfit1 = model1 . predict (X21)
yfit2 = model2 . predict (X22)
yfit3 = model3 . predict (X23)
yfit4 = model4 . predict (X24)
plt . scatter (x, y)
plt . plot (x, yfit1 );
plt . plot (x, yfit2 );
plt . plot (x, yfit3 );
plt . plot (x, yfit4 );
Scores:
0.9892183288409704
0.9939353099730458
1.0
1.0
On constate que plus on augmente le degré du polynôme, plus le modèle s'ajuste aux données et son score est élevé jusqu'à coller parfaitement aux données à
partir du degré 4. En revanche cela expose ces modèles au surajustement.
3.
a. Interpréter le segment de code qui suit
In [13]: from sklearn . preprocessing import PolynomialFeatures
from sklearn . linear_model import LinearRegression
from sklearn . pipeline import make_pipeline
def PolynomialRegression ( degree =2, ** kwargs ):
return make_pipeline ( PolynomialFeatures ( degree ), LinearRegression (** kwargs ))
La fonction PolynomialRegression crée un pipeline qui unifie les tâches de de création de création de la matrice et de création du modèle de régression linéaire en
une seule étape.
Pour la suite, nous considérons le jeu de données générées par la fonction qui suit
In [14]: import numpy as np
def make_data (N, err =1.0 , rseed =1):
# randomly sample the data
rng = np. random . RandomState ( rseed )
X = rng. rand (N, 1) ** 2
y = 10 - 1. / (X. ravel () + 0.1)
if err > 0:
y += err * rng. randn (N)
return X, y
X, y = make_data (40)
plt . figure ()
plt . scatter (X, y)
Out[14]: <matplotlib.collections.PathCollection at 0x20bc81f5da0>
HiQPdf Evaluation 08/22/2020
c. Comparez les modèles polynomiales (degree 1, 3, 5)
In [15]: import matplotlib . pyplot as plt
import seaborn ;
seaborn . set ()
X_test = np. linspace ( -0.1 , 1.1 , 500)[: , None ]
plt . figure ()
plt . scatter (X. ravel (), y, color ='black')
axis = plt. axis ()
for degree in [1, 3, 5]:
model = PolynomialRegression ( degree ). fit(X, y)
y_test = model.predict( X_test )
print("Modèle de degré",degree,":",model.score(X, y))
plt . plot ( X_test . ravel (), y_test , label ='degree ={0}'. format ( degree ))
plt . xlim ( -0.1 , 1.0)
plt . ylim (-2, 12)
plt . legend ( loc='best');
Modèle de degré 1 : 0.724324304506582
Modèle de degré 3 : 0.9328514024067205
Modèle de degré 5 : 0.9459786646758396
d. A l’aide des courbes de validation, étudier les degree en fonction du score
In [16]: from sklearn.model_selection import validation_curve
degree = np. arange (0, 21)
train_score , val_score = validation_curve (
PolynomialRegression (), X, y, 'polynomialfeatures__degree', degree , cv =7)
plt . figure ()
plt . plot ( degree , np. median ( train_score , 1), color ='blue',
label ='training score')
plt . plot ( degree , np. median ( val_score , 1), color ='red',
label ='validation score')
plt . legend ( loc='best')
plt . ylim (0, 1)
plt . xlabel ('degree')
plt . ylabel ('score');
Grâce à la courbe de validation, on constate que le degré 3 est celui qui offre le meilleur score de validation. Au delà du degré 16, le score de validation devient
nul.
e. Afficher les résultats obtenus sur des données réelles
In [17]: plt . figure ()
plt . scatter (X. ravel (), y) HiQPdf Evaluation 08/22/2020
lim = plt. axis ()
y_test = PolynomialRegression (3). fit(X, y). predict ( X_test )
plt . plot ( X_test . ravel (), y_test );
plt . axis ( lim );
f. Testez et interprétez le script qui suit
In [18]: from sklearn . model_selection import learning_curve
plt . figure ()
fig , ax = plt . subplots (1, 2, figsize =(16 , 6))
fig . subplots_adjust ( left =0.0625 , right =0.95 , wspace =0.1)
for i, degree in enumerate ([2 , 9]):
N, train_lc , val_lc = learning_curve ( PolynomialRegression ( degree ), X, y, cv =7,
train_sizes =np. linspace (0.3 , 1, 25))
ax[i]. plot (N, np. mean ( train_lc , 1), color ='blue', label ='training score')
ax[i]. plot (N, np. mean ( val_lc , 1), color ='red', label ='validation score')
ax[i]. hlines (np. mean ([ train_lc [-1], val_lc [ -1]]) , N[0] , N[-1], color ='gray', linestyle ='dashed')
ax[i]. set_ylim (0, 1)
ax[i]. set_xlim (N[0] , N[ -1])
ax[i]. set_xlabel ('training size')
ax[i]. set_ylabel ('score')
ax[i]. set_title ('degree = {0}'. format ( degree ), size =14)
ax[i]. legend (loc='best')
<Figure size 432x288 with 0 Axes>
Ce segment de code affiche la manière dont le score du modèle évolue lorsqu'on augmente progressivement la taille du jeu d'entrainement. Ainsi on constate
qu'une régression polynomiale de degré 2 atteint un score élevé avec bien moins de données qu'il n'en faut pour obtenir le même résultat avec une régression
polynomiale de degré 9.
Exercice 3
1. Charger le jeu de données
In [19]: import numpy as np
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import train_test_split
# Chargement des données
iris = datasets.load_iris()
X, y = iris.data[:, :2], iris.target
# On conserve 30% du jeu de données pour l'évaluation
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
2. Entrainer le modèle de régression logistique
In [20]: lr = LogisticRegression()
lr.fit(X_train, y_train)
lr.score(X_test, y_test)
Out[20]: 0.8444444444444444
HiQPdf Evaluation 08/22/2020
3. générer les probabilités estimées par le modèle pour les fleurs ayant des tailles de pétales comprises entre 0 et 3cm
In [21]: i = 0
abxcisses = [0,1,2]
for width in X_test[:, 1]:
if width < 3:
print("Largeur de la fleur:",width)
plt.bar(abxcisses,lr.predict_proba(X_test[i:i+1, :])[0],0.1)
plt.xlabel("Classes")
plt.ylabel("Probabilités")
plt.show()
i = i+1
Largeur de la fleur: 2.8
Largeur de la fleur: 2.7
Largeur de la fleur: 2.7
Largeur de la fleur: 2.4
Largeur de la fleur: 2.9
HiQPdf Evaluation 08/22/2020
Largeur de la fleur: 2.4
Largeur de la fleur: 2.9
Largeur de la fleur: 2.9
Largeur de la fleur: 2.5
Largeur de la fleur: 2.4
HiQPdf Evaluation 08/22/2020
Largeur de la fleur: 2.5
Largeur de la fleur: 2.9
Largeur de la fleur: 2.5
Largeur de la fleur: 2.2
Largeur de la fleur: 2.6
HiQPdf Evaluation 08/22/2020
4. Dans une même figure les courbes d’évolutions correspondantes
5. Interpéter les garphes et discuter sur la frontière de décision
6. Calculer la précision du modèle
In [22]: from sklearn.metrics import precision_score
y_pred = lr.predict(X_test)
print(precision_score(y_test, y_pred, average='macro'))
0.841354723707665
7.
a. Utiliser la régression softmax pour répartir les fleurs d’iris en trois classes
In [23]: softmax_reg = LogisticRegression(multi_class='multinomial',solver='lbfgs',C=10)
softmax_reg.fit(X_train, y_train)
softmax_reg.score(X_test, y_test)
Out[23]: 0.8444444444444444
b. Interpréter les résultats obtenus en vous basant sur les probabilités estimées et la frontière de décision.
In [24]: # Plot the decision boundary
x_min, x_max = X_train[:, 0].min() - .5, X_train[:, 0].max() + .5
y_min, y_max = X_train[:, 1].min() - .5, X_train[:, 1].max() + .5
h = .02 # step size in the mesh
xx, yy = np.meshgrid(np.arange(x_min, x_max, h), np.arange(y_min, y_max, h))
Z = softmax_reg.predict(np.c_[xx.ravel(), yy.ravel()])
# Put the result into a color plot
Z = Z.reshape(xx.shape)
plt.figure(1, figsize=(4, 3))
plt.pcolormesh(xx, yy, Z, cmap=plt.cm.Paired)
# Plot also the training points
plt.scatter(X[:, 0], X[:, 1], c=y, edgecolors='k', cmap=plt.cm.Paired)
plt.xlabel('Sepal length')
plt.ylabel('Sepal width')
plt.xlim(xx.min(), xx.max())
plt.ylim(yy.min(), yy.max())
plt.xticks(())
plt.yticks(())
plt.title("Frontière de décision Régression Softmax")
plt.show()
La frontière de décision de la régression softmax nous montre que les fleurs de la classe coloriée en bleu sont parfaitement classées tandis qu'il y a beaucoup de
fleurs des classes jaune et rouge qui sont mal classées. Cela explique le score moyen obtenu par softmax (0.822).
c. Impélenter une descente de gradient ordinaire avec arrêt précoce avec une régression softmax sans utiliser Scikit-Learn
In [25]: import numpy as np
import math HiQPdf Evaluation 08/22/2020
def sigma(t):
return 1/(1 + math.exp(-t))
def gradient(theta, X, y):
gradient = [] #Vecteur gradient
for i in range(len(theta)):
m = len(X)
grad_j = 0
for j in range(2):
#Gradient de la fonction coût de la régression Softmax
grad_j += (1/m)*(sigma((theta.T*X[i])[0]) - y[i])*X[i][j]
gradient.append(grad_j)
return gradient
def softmax_OGD(X, y, alpha=0.1):
theta0 = np.zeros(2) #Valeur initiale de theta
theta_actuel = theta0
iter = 0
while np.linalg.norm(gradient(theta_actuel, X, y)) > 0.1 and iter < 100:
grad = gradient(theta_actuel, X, y)
for i in range(2):
theta_actuel[i] = theta_actuel[i] - alpha * grad[i]
iter += 1
theta_final = theta_actuel
return theta_final
In [26]: softmax_OGD(X_train, y_train)
Out[26]: array([1.0733514 , 0.07955245])
Exercice 4
1.
a. Concevez un classificateur pour le jeu de données MNIST
In [27]: #Nécessite une connexion à internet
import pickle, gzip, urllib.request, json
import numpy as np
# On charge le jeu de données mnist
urllib.request.urlretrieve("http://deeplearning.net/data/mnist/mnist.pkl.gz", "mnist.pkl.gz")
with gzip.open('mnist.pkl.gz', 'rb') as f:
train_data, validation_data, test_data = pickle.load(f, encoding='latin1')
In [28]: import matplotlib.pyplot as plt
X_train, y_train = train_data[0], train_data[1]
print(X_train.shape, y_train.shape)
X_test, y_test = test_data[0], test_data[1]
print(X_test.shape, y_test.shape)
# get the first image and it's label
img1_arr, img1_label = X_train[0], y_train[0]
# reshape first image(1 D vector) to 2D dimension image
img1_2d = np.reshape(img1_arr, (28, 28))
# show it
plt.subplot(111)
plt.imshow(img1_2d, cmap=plt.get_cmap('gray'))
plt.show()
(50000, 784) (50000,)
(10000, 784) (10000,)
In [29]: from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100, random_state=0)
b. Ecrivez une fonction qui peut décaler une image MNIST d’un pixel dans une direction quelconque.
In [30]: def decale(img, n): #Déplace l'image de n pixels vers la droite
img_2d = np.reshape(img, (28, 28)) HiQPdf Evaluation 08/22/2020
new_img_2d = np.zeros([28,28])
for i in range(n):
new_img_2d[:, i:i+1] = np.zeros([28,1])
for i in range(n+1,28):
new_img_2d[:, i:i+1] = img_2d[:, i-n-1:i-n]
new_img = new_img_2d.reshape(784,)
return new_img
c. Puis, pour chaque image du jeu d’entraînement, créez quatre copies décalées et ajoutez les au jeu d’entraînement
for i in range(50000): img = X_train[i] img1 = decale(img,1) img2 = decale(img,2) img3 = decale(img,3) img4 = decale(img,4) X_train = np.append(X_train,(img1))
X_train = np.append(X_train,(img2)) X_train = np.append(X_train,(img3)) X_train = np.append(X_train,(img4)) for j in range(4): y_train = np.append(y_train,
(y_train[i])) print(X_train.shape, y_train.shape)
d. Ensuite entraînez votre meilleur modèle sur ce jeu d’entraînement étendu et mesurez son excatitude sur le jeu de test.
In [31]: clf.fit(X_train, y_train) #Modèle RandomForests précédent
clf.score(X_test, y_test)
Out[31]: 0.9685
e. Construire un classificateur de spam
iii. Partagez ces données entre jeu d’entraînement et jeu de test
In [32]: import os
import io
PATH_TO_HAM_DIR = "C:/Users/msi/ml_data/Mail-SpamAssassin-3.4.4/t/data/nice" #A changer selon l'emplacement de SpamAssassin
PATH_TO_SPAM_DIR = "C:/Users/msi/ml_data/Mail-SpamAssassin-3.4.4/t/data/spam" #A changer selon l'emplacement de SpamAssassin
X = [] #X représente l'input Data (ici les mails)
y = [] #les etiquettes (labels) pour le training set
def readFilesFromDirectory(path, classification):
os.chdir(path)
files_name = os.listdir(path)
for current_file in files_name:
message = extract_mail_body(current_file)
X.append(message)
y.append(classification)
def extract_mail_body(file_name_str):
inBody = False
lines = []
file_descriptor = io.open(file_name_str,'r', encoding='latin1')
for line in file_descriptor:
if inBody:
lines.append(line)
elif line == '\n':
inBody = True
message = '\n'.join(lines)
file_descriptor.close()
return message
readFilesFromDirectory(PATH_TO_HAM_DIR, 0) # 0 => HAM
readFilesFromDirectory(PATH_TO_SPAM_DIR, 1) # 1 => SPAM
print(len(X))
print(y)
74
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1
, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
iv. Ecrivez un pipeline de préparation de données pour convertir chaque e-mail en un vecteur de caractéristiques
In [33]: from sklearn.feature_extraction.text import CountVectorizer
vectorizer = CountVectorizer()
# On vectorise le jeu de données
vec = vectorizer.fit_transform(X)
In [45]: from sklearn.model_selection import train_test_split
# Jeu de données vectorisé
X_vec = vec.toarray()
print(X_vec.shape)
X_train_vec, X_test_vec, y_train, y_test = train_test_split(X_vec, y, test_size=0.3)
# On affiche le vecteur du premier e-mail
print(X_train_vec[0])
(74, 895113)
[0 0 8 ... 0 0 0]
In [46]: print(X_train_vec.shape, X_test_vec.shape)
(51, 895113) (23, 895113)
HiQPdf Evaluation 08/22/2020
v. Essayez ensuite différents classificateurs et en deduire un bon classifieur de spam, ayant à la fois un rappel et une précision élevée
In [51]: from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import recall_score
from sklearn.metrics import precision_score
#Régression logistique
log_reg = LogisticRegression()
log_reg.fit(X_train_vec, y_train)
y_pred = log_reg.predict(X_test_vec)
print("Régression logistique: Rappel =>",recall_score(y_test, y_pred),"Précision =>",precision_score(y_test, y_pred))
#Random Forests
rf = RandomForestClassifier(n_estimators=10)
rf.fit(X_train_vec, y_train)
y_pred = rf.predict(X_test_vec)
print("Random Forests: Rappel =>",recall_score(y_test, y_pred),"Précision =>",precision_score(y_test, y_pred))
Régression logistique: Rappel => 0.6923076923076923 Précision => 0.6923076923076923
Random Forests: Rappel => 0.7692307692307693 Précision => 0.5555555555555556
Random forests présente un rappel plus élevé mais une précision moindre que la régression logistique. Pour ses 2 scores assez élevés, on conclura donc que la
régression logistique est un bon classifieur de spams.