import numpy as np
import matplotlib.pyplot as plt
n = 15
x = 2*np.random.random_sample(n)-1
x
def g(x):
return 1.5*x**3 - x**2 - .75*x + 1
y = g(x) + .05*np.random.randn(n)
y
plt.scatter(x,y)
plt.show()
n_test = 30
x_test = 2*np.random.random_sample(n_test)-1
y_test = g(x_test) + .05*np.random.randn(n_test)
from sklearn.linear_model import LinearRegression
f = LinearRegression()
X = x[:,np.newaxis]
X_test = x_test[:,np.newaxis]
f.fit(X,y)
xplot = np.linspace(-1,1,500).reshape(-1,1)
plt.scatter(x,y)
plt.plot(xplot,f.predict(xplot))
plt.show()
print("Erreur moyenne d'apprentissage :", sum((y-f.predict(X))**2)/n)
print("Erreur moyenne de test :", sum((y_test-f.predict(X_test))**2)/n_test)
from sklearn.preprocessing import PolynomialFeatures
psi = PolynomialFeatures(2,include_bias=False).fit_transform
f = LinearRegression().fit(psi(X),y)
plt.scatter(x,y)
plt.plot(xplot,f.predict(psi(xplot)))
plt.show()
print("Erreur moyenne d'apprentissage :", sum((y-f.predict(psi(X)))**2)/n)
print("Erreur moyenne de test :", sum((y_test-f.predict(psi(X_test)))**2)/n_test)
On observe une nette amélioration par rapport à la regression linéaire
def reg_poly(d):
psi = PolynomialFeatures(d,include_bias=False).fit_transform
return LinearRegression().fit(psi(X),y), psi
plt.scatter(x,y)
poly = {}
psi = {}
for d in [3,4,13,14]:
poly[d], psi[d] = reg_poly(d)
plt.plot(xplot,poly[d].predict(psi[d](xplot)))
plt.axis([-1, 1, -1.5, 1.5])
plt.legend(['d = 3', 'd = 4', 'd = 13', 'd = 14','données'])
plt.show()
print(poly[3].intercept_)
print(poly[3].coef_)
Pour n=3, ces coefficients sont similaires à ceux de la fonction g Pour n=14, il existe un polynôme qui passe par chacun des 15 points (polynôme d'interpolation de Lagrange). Ce polynôme minimise évidemment le risque empirique, c'est donc celui donné par la minimisation du risque empirique.
mean_train_error = []
mean_test_error = []
d_max = 14
for d in range(1,d_max+1):
f, psi = reg_poly(d)
mean_train_error.append(sum((f.predict(psi(X))-y)**2)/n)
mean_test_error.append(sum((f.predict(psi(X_test))-y_test)**2)/n_test)
plt.plot(range(1,d_max+1),mean_train_error)
plt.plot(range(1,d_max+1),mean_test_error)
plt.axis([0, d_max, 0, .2])
plt.show()
Plus n est élevé, plus les polyômes obtenus sont complexes et plus l'erreur d'apprentissage est faible.
L'erreur de test décroît d'abord. Puis, lorsque n grand, il croît: il y a alors sur-apprentissage. La grande complexité des polynôme permet de mieux coller aux points d'apprentissage, mais ne permet pas une bonne généralisation à de nouveaux points.
from sklearn.linear_model import Lasso
def reg_poly_lasso(d, alpha=1):
psi = PolynomialFeatures(d,include_bias=False).fit_transform
return Lasso(alpha).fit(psi(X),y), psi
for alpha in [10**a for a in range(-6,1)]:
f, psi = reg_poly_lasso(14,alpha)
plt.scatter(x,y)
plt.plot(xplot,f.predict(psi(xplot)))
plt.axis([-1, 1, -1.5, 1.5])
print('Coefficients du polynôme :',f.coef_)
plt.show()
Pour des valeurs de alpha assez grands, l'algorithme produit des polynômes ayant beaucoup de coefficients nuls et de faible degré. Cela limite la complexité des polynômes et donc le sur-apprentissage.
mean_train_error = []
mean_test_error = []
nonzero_coefficients = []
degree = []
alpha_range = [10**a for a in range(-6,1)]
for alpha in alpha_range:
f, psi = reg_poly_lasso(14,alpha)
mean_train_error.append(sum((f.predict(psi(X))-y)**2)/n)
mean_test_error.append(sum((f.predict(psi(X_test))-y_test)**2)/n_test)
plt.plot(alpha_range,mean_train_error)
plt.plot(alpha_range,mean_test_error)
plt.xscale('log')
plt.yscale('log')
plt.show()
Le paramètre alpha joue un rôle similaire à d dans la question 8 (mais en sens inverse).
Lorsque alpha décroît, les polynômes obtenus sont de plus en plus complexes, et l'erreur d'apprentissage diminue. Mais quand alpha est assez petit, l'erreur de test augmente à nouveau: il y a alors sur-apprentissage.