Skip to content

Instantly share code, notes, and snippets.

@Qu3tzal
Created February 21, 2019 02:10
Show Gist options
  • Save Qu3tzal/838674eca4b7861132dd4abf8e7a6dd7 to your computer and use it in GitHub Desktop.
Save Qu3tzal/838674eca4b7861132dd4abf8e7a6dd7 to your computer and use it in GitHub Desktop.
solution_regression.py
# -*- 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