1) Question : (cf ex1 q1)
Quel est l'intérêt de prendre l'esperance des risques ? En effet, les risques semblent déterministes...
Réponse : $$\mathcal{R}(f) = \mathbb{E}_{(X,Y) \sim P}[l(f(X), Y)]$$
$$\eta(x) = \mathbb{E}[Y|X=x]$$Si $f^*(x) = \mathbb{1}\{\eta(x) \geq \frac{1}{2}\}$ alors $R(f^*)$ est bien déterministe
Cependant si $\hat{f}$ dépend des v.a $\mathcal{D}_n = \{(X_1, Y_1), \cdots, (X_n, Y_n)\}$, ce qui est souvent le cas, alors le risque (conditionnel) peut s'écrire
$$ \mathcal{R}(\hat{f}) = \mathcal{R}(\hat{f}(\mathcal{D}_n)) = \mathbb{E}_{(X,Y) \sim P}[\ l(\hat f(\mathcal{D}_n, X), Y) \ |\ \mathcal{D}_n] $$Nous appelons alors le risque moyen
$$ \mathbb{E}[\mathcal{R}(\hat{f})] = \mathbb{E}[\ l(\hat f(\mathcal{D}_n, X), Y) \ ] $$2) Question : (cf ex2)
Au moment de l'IPP en primitivant $\pi(\theta | x)$ on passe d'une intégration sur $\theta$ a une intégration sur une autre variable $y$, pourquoi ?
Réponse :
Ici, $y$ << correspond à $\theta$ la variable locale>>. Au fait, il y a $\theta$ signifie deux notations ...
Afin de ne pas écrire $P^\pi(\theta < \theta | x)$, j'ai changé la variable locale $\theta$ en $y$.
import numpy as np
import matplotlib.pyplot as plt
Z = np.zeros((8,8))
Z[1::2,::2] = 1
Z[::2,1::2] = 1
Z
M = np.arange(1,21)
M = M.reshape((5,4))
M = M.transpose()
print(M)
print(M[1:,:][:,[1,4,2]])
m = 15
x = 2*np.random.random_sample(m)-1
def g(x):
return 1.5*x**3 - x**2 - .75*x + 1
y = g(x) + .05*np.random.randn(m)
plt.plot(x,y,'bo')
plt.show()
m_test = 30
x_test = 2*np.random.random_sample(m_test)-1
y_test = g(x_test) + .05*np.random.randn(m_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.plot(x,y,'bo')
plt.plot(xplot,f.predict(xplot))
plt.show()
print(sum((y-f.predict(X))**2)/m)
print(sum((y_test-f.predict(X_test))**2)/m_test)
from sklearn.preprocessing import PolynomialFeatures
psi = PolynomialFeatures(2,include_bias=False).fit_transform
f = LinearRegression().fit(psi(X),y)
plt.plot(x,y,'bo')
plt.plot(xplot,f.predict(psi(xplot)))
plt.show()
print(sum((y-f.predict(psi(X)))**2)/m)
print(sum((y_test-f.predict(psi(X_test)))**2)/m_test)
On observe une nette amélioration par rapport à la regression linéaire
def reg_poly(n):
psi = PolynomialFeatures(n,include_bias=False).fit_transform
return LinearRegression().fit(psi(X),y), psi
plt.plot(x,y,'bo')
poly = {}
psi = {}
for n in [3,4,13,14]:
poly[n], psi[n] = reg_poly(n)
plt.plot(xplot,poly[n].predict(psi[n](xplot)))
plt.axis([-1, 1, -1.5, 1.5])
plt.legend(['données','n = 3', 'n = 4', 'n = 13', 'n = 14'])
plt.show()
print(poly[3].intercept_)
print(poly[3].coef_)
def reg_poly(n):
psi = PolynomialFeatures(n,include_bias=True).fit_transform
return LinearRegression().fit(psi(X),y), psi
plt.plot(x,y,'bo')
poly = {}
psi = {}
for n in [3,4,13,14]:
poly[n], psi[n] = reg_poly(n)
plt.plot(xplot,poly[n].predict(psi[n](xplot)))
plt.axis([-1, 1, -1.5, 1.5])
plt.legend(['données','n = 3', 'n = 4', 'n = 13', 'n = 14'])
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 = []
n_max = 14
for n in range(1,n_max+1):
f, psi = reg_poly(n)
mean_train_error.append(sum((f.predict(psi(X))-y)**2)/m)
mean_test_error.append(sum((f.predict(psi(X_test))-y_test)**2)/m_test)
plt.plot(range(1,n_max+1),mean_train_error)
plt.plot(range(1,n_max+1),mean_test_error)
plt.axis([0, n_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(n, alpha=1):
psi = PolynomialFeatures(n,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.plot(x,y,'bo')
plt.plot(xplot,f.predict(psi(xplot)))
plt.axis([-1, 1, -1.5, 1.5])
print('Coefficients:',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)/m)
mean_test_error.append(sum((f.predict(psi(X_test))-y_test)**2)/m_test)
plt.plot(np.log10(alpha_range),mean_train_error)
plt.plot(np.log10(alpha_range),mean_test_error)
plt.axis([-6,0,0,0.5])
plt.show()
Le paramètre alpha joue un rôle similaire à n dans la question 10 (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.
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
iris = sns.load_dataset("iris")
iris.head()
sns.set()
sns.pairplot(iris, hue="species");
plt.show()
Les deux variables explicatives qui semblent le mieux séparer les espèces sont sepal_with
et petal_length
X = iris.values[:,1:3]
y = iris.values[:,4]
X_train = X[:90]
y_train = y[:90]
X_test = X[90:]
y_test = y[90:]
Les données X
et y
n'étaient pas mélangées: les espèces sont regroupées. En particulier, l'échantillon de test ne contient quasiment que des espèces virginica, alors que l'échantillon d'apprentissage ne contient aucune espèce virginica. Cela fausserait donc et l'apprentissage et le test. Il faut donc au préalable mélanger le jeu de données.
from sklearn.utils import shuffle
X, y = shuffle(X,y)
X_train = X[:90]
y_train = y[:90]
X_test = X[90:]
y_test = y[90:]
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=3)
knn.fit(X_train, y_train)
print(knn.score(X_train,y_train))
print(knn.score(X_test,y_test))
Le score empirique mesure la proportion de bonnes prédictions, alors que le risque empirique mesure la proportion de mauvaises prédictions (lorsqu la fonction de perte considérée est la perte 0-1). Donc: score = 1 - risque empirique
knn = {}
score_train = []
score_test = []
k_range = range(1,21)
for k in k_range:
knn[k] = KNeighborsClassifier(n_neighbors=k)
knn[k].fit(X_train,y_train)
score_train.append(knn[k].score(X_train,y_train))
score_test.append(knn[k].score(X_test,y_test))
plt.plot(list(k_range),score_train)
plt.plot(list(k_range),score_test)
plt.show()
La valeur k=6
semble ici donner le meilleur score de test.
def best_knn_score(X,y):
k_range=range(1,21)
score_test = []
X, y = shuffle(X,y)
X_train = X[:90]
y_train = y[:90]
X_test = X[90:]
y_test = y[90:]
for k in k_range:
knn = KNeighborsClassifier(n_neighbors=k)
knn.fit(X_train,y_train)
score_test.append(knn.score(X_test,y_test))
return max(score_test)
print(best_knn_score(X,y))
print(best_knn_score(X,y))
print(best_knn_score(X,y))
Le résultat est différent à chaque fois. Cela est dû à au mélange aléatoire des données par shuffle(X,y)
.
def best_knn_score_avg(X,y):
scores = []
for i in range(100):
scores.append(best_knn_score(X,y))
return np.mean(scores)
print(best_knn_score_avg(X,y))
X_ = X.copy()
X_[:,0] = X_[:,0]/100
print(best_knn_score_avg(X_,y))
Le score reste similaire
X_ = X.copy()
X_[:,1] = X_[:,1]/100
print(best_knn_score_avg(X_,y))
Le score est cette fois-ci détérioré.
from sklearn import preprocessing
X_scaled = preprocessing.scale(X)
print(best_knn_score_avg(X_scaled,y))
En l'occurence, cela n'améliore pas le score, il est même légèrement détérioré.
X = iris.values[:,0:4]
y = iris.values[:,4]
print(best_knn_score_avg(X,y))
Le score est meilleur.