.. _artificielshaperst: ======================================== Intuition derrière l’érosion des modèles ======================================== .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`PDF `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/lectures/artificiel_shape.ipynb|*` La plupart des modèles de machine learning doivent être rafraîchi régulièrement. Quelques intuitions derrière ce phénomène. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: .. code:: ipython3 %matplotlib inline Des données très simples. ------------------------- On simule un jeu de données pour une régression en deux dimensions : :math:`y= \frac{x}{2}+1 + \epsilon`. .. code:: ipython3 from papierstat.datasets import line2d xy = line2d(100) xy[:5] .. parsed-literal:: array([[7.9779153 , 4.8650553 ], [2.45296688, 1.69489011], [5.70750602, 3.47846646], [4.81633352, 3.41515132], [0.04393984, 0.99115227]]) .. code:: ipython3 import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 1, figsize=(4, 4)) ax.plot(xy[:, 0], xy[:, 1], '.') ax.set_title('Données pour une régression'); .. image:: artificiel_shape_5_0.png Régression linéaire ------------------- C’est le modèle idéal pour ces données. .. code:: ipython3 from sklearn.linear_model import LinearRegression clr = LinearRegression() clr.fit(xy[:, 0:1], xy[:, 1]) .. parsed-literal:: LinearRegression(copy_X=True, fit_intercept=True, n_jobs=1, normalize=False) .. code:: ipython3 pred = clr.predict(xy[:, 0:1]) fig, ax = plt.subplots(1, 1, figsize=(4, 4)) ax.plot(xy[:, 0], xy[:, 1], '.', label="données") ax.plot(xy[:, 0], pred, '.', label="prédiction") ax.set_title('Prévision avec la régression linéaire'); .. image:: artificiel_shape_8_0.png C’est le graphe le plus classique qui soit. Mais on ne se pose jamais la question de ce qu’il se passe en dehors de l’intervalle initial. .. code:: ipython3 from numpy.random import rand n = 100 newx = (rand(n) * 20 - 5).reshape(n, 1) pred = clr.predict(newx) fig, ax = plt.subplots(1, 1, figsize=(4, 4)) ax.plot(xy[:, 0], xy[:, 1], '.', label="données") ax.plot(newx, pred, '.', label="prédiction") ax.set_title('Prévision étendue avec la régression linéaire'); .. image:: artificiel_shape_10_0.png Cela paraît plutôt censé de prolonger les prédictions en ce sens. Voyons ce qu’il se passe avec d’autres modèles. Autres modèles -------------- .. code:: ipython3 from sklearn.neural_network import MLPRegressor mlp = MLPRegressor() mlp.fit(xy[:, :1], xy[:, 1]) .. parsed-literal:: MLPRegressor(activation='relu', alpha=0.0001, batch_size='auto', beta_1=0.9, beta_2=0.999, early_stopping=False, epsilon=1e-08, hidden_layer_sizes=(100,), learning_rate='constant', learning_rate_init=0.001, max_iter=200, momentum=0.9, nesterovs_momentum=True, power_t=0.5, random_state=None, shuffle=True, solver='adam', tol=0.0001, validation_fraction=0.1, verbose=False, warm_start=False) .. code:: ipython3 pred = mlp.predict(newx) fig, ax = plt.subplots(1, 1, figsize=(4, 4)) ax.plot(xy[:, 0], xy[:, 1], '.', label="données") ax.plot(newx, pred, '.', label="prédiction") ax.set_title('Prévision étendue avec le réseau de neurones'); .. image:: artificiel_shape_14_0.png Essayons avec une autre fonction d’activation. .. code:: ipython3 mlp = MLPRegressor(activation='tanh') mlp.fit(xy[:, :1], xy[:, 1]) pred = mlp.predict(newx) fig, ax = plt.subplots(1, 1, figsize=(4, 4)) ax.plot(xy[:, 0], xy[:, 1], '.', label="données") ax.plot(newx, pred, '.', label="prédiction") ax.set_title('Prévision étendue avec le réseau de neurones - logistic'); .. parsed-literal:: c:\python365_x64\lib\site-packages\sklearn\neural_network\multilayer_perceptron.py:564: ConvergenceWarning: Stochastic Optimizer: Maximum iterations (200) reached and the optimization hasn't converged yet. % self.max_iter, ConvergenceWarning) .. image:: artificiel_shape_16_1.png Si la prédiction est la même dans l’intervalle qui correspond aux données initiales, en dehors de celui-ci la prédiction est complètement différente. Voyons avec un arbre de décision ou une random forest. .. code:: ipython3 from sklearn.ensemble import RandomForestRegressor from sklearn.tree import DecisionTreeRegressor rf = RandomForestRegressor() tr = DecisionTreeRegressor() rf.fit(xy[:, :1], xy[:, 1]) tr.fit(xy[:, :1], xy[:, 1]) prrf = rf.predict(newx) trrf = tr.predict(newx) fig, ax = plt.subplots(1, 2, figsize=(10, 4)) ax[0].plot(xy[:, 0], xy[:, 1], '.', label="données") ax[1].plot(xy[:, 0], xy[:, 1], '.', label="données") ax[0].plot(newx, prrf, '.', label="Random Forest") ax[1].plot(newx, trrf, '.', label="Decision Tree") ax[0].set_title('Prévision étendue avec une forêt') ax[1].set_title('Prévision étendue avec un arbre'); .. image:: artificiel_shape_19_0.png Interprétation -------------- Il faut retenir que ce jeu de données artificiel possède une tendance : il n’est pas stationnaire. C’est le cas de beaucoup de jeu de données liés à l’activité humaine, données web, population… Il est très rare d’avoir un jeu de données stationnaires. Cela veut dire que plus le temps avance, plus les données dérivent. Un modèle est appris à un instant :math:`t`, selon le modèle choisi, il aura plus ou moins de mal à s’adapter à cette dérive. Les modèles non linéaires sont plus performances mais généralisent souvent très mal si les données s’éloignent trop des données utilisées pour apprendre. Il faut donc les réappendre régulièrement pour compenser la perte de performance en prédiction.