Created
February 21, 2019 02:10
-
-
Save Qu3tzal/838674eca4b7861132dd4abf8e7a6dd7 to your computer and use it in GitHub Desktop.
solution_regression.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
##### | |
# Maxime Alvarez 18085322 | |
# Daniel Regnard 18130194 | |
### | |
import numpy as np | |
import random | |
from sklearn import linear_model | |
from sklearn.metrics import mean_squared_error | |
class Regression: | |
def __init__(self, lamb, m=1): | |
self.lamb = lamb | |
self.w = None | |
self.M = m | |
def fonction_base_polynomiale(self, x): | |
""" | |
Fonction de base qui projette la donnee x vers un espace polynomial tel que mentionne au chapitre 3. | |
Si x est un scalaire, alors phi_x sera un vecteur à self.M dimensions : (x^1,x^2,...,x^self.M) | |
Si x est un vecteur de N scalaires, alors phi_x sera un tableau 2D de taille NxM | |
NOTE : En mettant phi_x = x, on a une fonction de base lineaire qui fonctionne pour une regression lineaire | |
""" | |
phi_x = x | |
if np.isscalar(x) or len(x) < 2: | |
if not np.isscalar(x): | |
x = x[0] | |
phi_x = np.zeros(shape=(self.M + 1,)) | |
for i in range(len(phi_x)): | |
phi_x[i] = x ** i | |
else: | |
matrix = np.zeros(shape=(len(x), self.M + 1)) | |
for i in range(matrix.shape[0]): | |
for j in range(matrix.shape[1]): | |
matrix[i][j] = x[i] ** j | |
phi_x = matrix | |
return phi_x | |
def recherche_hyperparametre(self, X, t): | |
""" | |
Validation croisee de type "k-fold" pour k=10 utilisee pour trouver la meilleure valeur pour | |
l'hyper-parametre self.M. | |
Le resultat est mis dans la variable self.M | |
X: vecteur de donnees | |
t: vecteur de cibles | |
""" | |
best_error = np.inf | |
best_M = 0 | |
best_weights = None | |
# Zip (explicit call to list to prevent lazy evaluation) | |
data = list(zip(X, t)) | |
# 11 is arbitrary | |
for current_M in range(1, 11): | |
error_array = [] | |
self.M = current_M | |
for k in range(10): | |
# Shuffle | |
random.shuffle(data) | |
# Separate X and targets | |
X_all = [x_i for x_i, _ in data] | |
T_all = [t_i for _, t_i in data] | |
# Split the data in training and validation data | |
split_index = int(0.9 * len(X_all)) # We take 90% for training and 10% for validation | |
X_training = X_all[:split_index] | |
T_training = T_all[:split_index] | |
X_validation = X_all[split_index:] | |
T_validation = T_all[split_index:] | |
# Train | |
self.entrainement(X_training, T_training, self.using_sklearn) | |
# Predict values for X_validation | |
Y_predicted = [self.prediction(x_i) for x_i in X_validation] | |
# Compute error between T_validation and Y_predicted | |
error_value = mean_squared_error(T_validation, Y_predicted) | |
error_array.append(error_value) | |
# Check the mean error over the k-folds. | |
k_fold_error = np.asarray(error_array).mean() | |
if k_fold_error < best_error: | |
best_error = k_fold_error | |
best_M = current_M | |
self.M = best_M | |
def entrainement(self, X, t, using_sklearn=False): | |
""" | |
Entraîne la regression lineaire sur l'ensemble d'entraînement forme des | |
entrees ``X`` (un tableau 2D Numpy, ou la n-ieme rangee correspond à l'entree | |
x_n) et des cibles ``t`` (un tableau 1D Numpy ou le | |
n-ieme element correspond à la cible t_n). L'entraînement doit | |
utiliser le poids de regularisation specifie par ``self.lamb``. | |
Cette methode doit assigner le champs ``self.w`` au vecteur | |
(tableau Numpy 1D) de taille D+1, tel que specifie à la section 3.1.4 | |
du livre de Bishop. | |
Lorsque using_sklearn=True, vous devez utiliser la classe "Ridge" de | |
la librairie sklearn (voir http://scikit-learn.org/stable/modules/linear_model.html) | |
Lorsque using_sklearn=Fasle, vous devez implementer l'equation 3.28 du | |
livre de Bishop. Il est suggere que le calcul de ``self.w`` n'utilise | |
pas d'inversion de matrice, mais utilise plutôt une procedure | |
de resolution de systeme d'equations lineaires (voir np.linalg.solve). | |
Aussi, la variable membre self.M sert à projeter les variables X vers un espace polynomiale de degre M | |
(voir fonction self.fonction_base_polynomiale()) | |
NOTE IMPORTANTE : lorsque self.M < 0, il faut trouver la bonne valeur de self.M | |
""" | |
self.using_sklearn = using_sklearn | |
if self.M < 0: | |
self.recherche_hyperparametre(X, t) | |
print("Found M:", self.M) | |
phi_x = self.fonction_base_polynomiale(np.asarray(X)) | |
self.w = [0, 1] | |
if using_sklearn: | |
regression = linear_model.Ridge(alpha=self.lamb) | |
regression.fit(phi_x, t) | |
self.w = np.zeros((self.M + 1)) | |
self.w[0] = regression.intercept_ | |
for i in range(1, len(regression.coef_)): | |
self.w[i] = regression.coef_[i] | |
else: | |
A = self.lamb * np.eye(self.M) + np.dot(phi_x.T, phi_x) | |
B = np.dot(phi_x.T, t) | |
self.w = np.linalg.solve(A, B) | |
def prediction(self, x): | |
""" | |
Retourne la prediction de la regression lineaire | |
pour une entree, representee par un tableau 1D Numpy ``x``. | |
Cette methode suppose que la methode ``entrainement()`` | |
a prealablement ete appelee. Elle doit utiliser le champs ``self.w`` | |
afin de calculer la prediction y(x,w) (equation 3.1 et 3.3). | |
""" | |
phi_x = self.fonction_base_polynomiale(x) | |
return np.dot(self.w, phi_x) | |
@staticmethod | |
def erreur(t, prediction): | |
""" | |
Retourne l'erreur de la difference au carre entre | |
la cible ``t`` et la prediction ``prediction``. | |
""" | |
return np.power(float(prediction) - float(t), 2.0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment