.. _gradientboostingrst: ================= Gradient Boosting ================= .. only:: html **Links:** :download:`notebook `, :downloadlink:`html `, :download:`python `, :downloadlink:`slides `, :githublink:`GitHub|_doc/notebooks/td2a_ml/gradient_boosting.ipynb|*` Le notebook explore l’algorithme du `Gradient Boosting `__. .. code:: ipython3 from jyquickhelper import add_notebook_menu add_notebook_menu() .. contents:: :local: .. code:: ipython3 %matplotlib inline Premier exemple --------------- On considère les paramètres par défaut de la classe `GradientBoostingRegressor `__. .. code:: ipython3 from numpy.random import randn, random from pandas import DataFrame from sklearn.model_selection import train_test_split rnd = randn(1000) X = random(1000) * 8 - 4 y = X ** 2 - X + rnd * 2 + 150 # X^2 - X + 150 + epsilon X = X.reshape((-1, 1)) X_train, X_test, y_train, y_test = train_test_split(X, y) df = DataFrame({'X': X_train.ravel(), 'y': y_train}) ax = df.plot(x='X', y='y', kind='scatter') ax.set_title("Nuage de points X^2 - X + 150 + epsilon"); .. image:: gradient_boosting_4_0.png .. code:: ipython3 from sklearn.ensemble import GradientBoostingRegressor model = GradientBoostingRegressor(max_depth=1) model.fit(X_train, y_train) .. parsed-literal:: GradientBoostingRegressor(alpha=0.9, ccp_alpha=0.0, criterion='friedman_mse', init=None, learning_rate=0.1, loss='ls', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_iter_no_change=None, presort='deprecated', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False) .. code:: ipython3 import numpy ind = numpy.argsort(X_test, axis=0) y_ = model.predict(X_test) df = DataFrame({'X': X_test[ind].ravel(), 'y': y_test[ind].ravel(), 'y^': y_[ind].ravel()}) ax = df.plot(x='X', y='y', kind='scatter') df.plot(x='X', y='y^', kind='line', ax=ax, color="r") ax.set_title("Prédictions avec GradientBoostingRegressor"); .. image:: gradient_boosting_6_0.png Rien d’imprévu jusque là. Essayons autre chose. On regarde avec une seule itération. .. code:: ipython3 model = GradientBoostingRegressor(max_depth=1, n_estimators=1, learning_rate=0.5) model.fit(X_train, y_train) .. parsed-literal:: GradientBoostingRegressor(alpha=0.9, ccp_alpha=0.0, criterion='friedman_mse', init=None, learning_rate=0.5, loss='ls', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=1, n_iter_no_change=None, presort='deprecated', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False) .. code:: ipython3 y_ = model.predict(X_test) df = DataFrame({'X': X_test[ind].ravel(), 'y': y_test[ind].ravel(), 'y^': y_[ind].ravel()}) ax = df.plot(x='X', y='y', kind='scatter') df.plot(x='X', y='y^', kind='line', ax=ax, color="r") ax.set_title("Prédictions avec GradientBoostingRegressor\net une fonction en escalier"); .. image:: gradient_boosting_9_0.png Essayons de montrer l’évolution de la courbe prédite en fonction du nombre de marches et revenons à 100 estimateurs. .. code:: ipython3 model = GradientBoostingRegressor(max_depth=1) model.fit(X_train, y_train) .. parsed-literal:: GradientBoostingRegressor(alpha=0.9, ccp_alpha=0.0, criterion='friedman_mse', init=None, learning_rate=0.1, loss='ls', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_iter_no_change=None, presort='deprecated', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False) .. code:: ipython3 for i in range(0, model.estimators_.shape[0] + 1, 10): if i == 0: df = DataFrame({'X': X_test[ind].ravel(), 'y': y_test[ind].ravel()}) ax = df.plot(x='X', y='y', kind='scatter', figsize=(10, 4)) y_ = model.init_.predict(X_test) color = 'b' else: y_ = sum([model.init_.predict(X_test)] + [model.estimators_[k, 0].predict(X_test) * model.learning_rate for k in range(0, i)]) color = 'r' df = DataFrame({'X': X_test[ind].ravel(), 'y^': y_[ind].ravel()}) df.plot(x='X', y='y^', kind='line', ax=ax, color=color, label='i=%d' % i) ax.set_title("Prédictions"); .. image:: gradient_boosting_12_0.png learning rate et itérations --------------------------- Et si on choisissait un *learning_rate*, plus petit ou plus grand… .. code:: ipython3 model01 = GradientBoostingRegressor(max_depth=1, learning_rate=0.01) model01.fit(X_train, y_train) modela = GradientBoostingRegressor(max_depth=1, learning_rate=1.2) modela.fit(X_train, y_train) modelb = GradientBoostingRegressor(max_depth=1, learning_rate=1.99) modelb.fit(X_train, y_train) .. parsed-literal:: GradientBoostingRegressor(alpha=0.9, ccp_alpha=0.0, criterion='friedman_mse', init=None, learning_rate=1.99, loss='ls', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_iter_no_change=None, presort='deprecated', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False) .. code:: ipython3 import matplotlib.pyplot as plt fig, ax = plt.subplots(1, 3, figsize=(12, 4)) ind = numpy.argsort(X_test, axis=0) for i, mod in enumerate([model01, modela, modelb]): df = DataFrame({'X': X_test[ind].ravel(), 'y': y_test[ind].ravel(), 'y^': mod.predict(X_test)[ind].ravel()}) df.plot(x='X', y='y', kind='scatter', ax=ax[i]) df.plot(x='X', y='y^', kind='line', ax=ax[i], color="r") ax[i].set_title("learning_rate=%f" % mod.learning_rate); .. image:: gradient_boosting_15_0.png Une trop faible valeur de *learning_rate* semble retenir le modèle de converger, une grande valeur produit des effets imprévisibles. Pour comprendre pourquoi, il faut détailler l’algorithme… L’algorithme ------------ Inspiration ~~~~~~~~~~~ L’algorithme est inspiré de l’algorithme de la descente de gradient. On considère une fonction réelle :math:`f(x)` et on calcule le gradient :math:`\frac{\partial f}{\partial x}(x)` pour construire une suite : .. math:: x_{t+1} = x_t - \epsilon_t \frac{\partial f}{\partial x}(x_t) La suite :math:`(x_t)` converge vers le minimum de la fonction :math:`f`. On applique cela à une fonction d’erreur issue d’un problème de régression. .. math:: f(x) = \sum_{n=1}^N l(F(X_i), y_i) Le plus souvent, on applique cette méthode à une fonction :math:`F` qui dépend d’un paramètre :math:`\theta` .. math:: f(\theta, x) = \sum_{n=1}^N l(F(\theta, X_i), y_i) Et c’est la suite :math:`\theta_{t+1} = \theta_t - \epsilon_t \frac{\partial f}{\partial \theta}(\theta_t)` qui converge vers le minimum de la fonction :math:`f` de sorte que la fonction :math:`f(\theta, x)` approxime au mieux les points :math:`(X_i, y_i)`. Mais, on pourrait tout-à-fait résoudre ce problème dans un espace de fonctions et non un espace de paramètres : .. math:: G_{t+1} = G_t - \epsilon_t \frac{\partial f}{\partial G}(G_t) Le gradient :math:`\frac{\partial f}{\partial G}` est facile à calculer puisqu’il ne dépend pas de :math:`G`. On pourrait donc construire la fonction de régression :math:`G` comme une suite additive de fonctions :math:`F_k \sim - \epsilon_t \frac{\partial f}{\partial G}(G_t)`. .. math:: G_t = \sum_{k=1}^t F_k Et nous pourrions construire la fonction :math:`F_k` comme solution d’un problème de régression défini par les couples :math:`(X_i, z_i)` avec : .. math:: \begin{array}{rcl} z_i &=& - \epsilon_t \frac{\partial f}{\partial G}(G_t(X_i), y_i) \\ f(X_i, y_i) &=& l(G_t(X_i), y_i)\end{array} Voilà l’idée. Algorithme ~~~~~~~~~~ Je reprends ici la page wikipedia. On cherche à construire un modèle qui minimise l’erreur :math:`L(y,F(x)) = \sum_{i=1}^n l(y_i, F(X_i))`. On note :math:`r` le learning rate. **Etape 1 :** on cale un premier modèle de régression, ici, simplement une constante, en optimisant :math:`F_0(x) = \arg \min_\gamma \sum_{i=1}^n L(y_i, \gamma)`. :math:`F_0(x)` est une constante. On note ensuite :math:`F_m(x) = \gamma_0 \sum_{k=1}^m r \gamma_k h_k(x)` où :math:`\gamma_0` est la fonction constante construire lors de la première étape. **Etape 2 :** on calcule ensuite les erreurs :math:`e_{im} = l(y_i, F_m(x_i))` et l’opposé du gradient :math:`r_{im} = - \left[ \frac{\partial l(y_i, F_m(x_i)) }{\partial F_m(x_i)} \right]` **Etape 3 :** on choisit la fonction :math:`h_{m+1}(x)` de telle sorte qu’elle approxime au mieux les résidus :math:`r_{im}`. **Etape 4 :** on choisit le coefficient :math:`\gamma_{m+1}` de telle sorte qu’il minimise l’expression :math:`\min_\gamma \sum_{i=1}^n l\left(y_i, \gamma_0 + \sum_{k=1}^m r \gamma_k h_k(x_i) + \gamma h_{m+1}(x_i)\right)`. On retourne l’étape 2 autant de fois qu’il y a d’itérations. Lorsque l’erreur est une erreur quadratique :math:`l(y, F(x)) = (y-F(x))^2`, les résidus deviennent :math:`r_{im} = -2 (y_i - F_m(x_i))`. Par conséquent, la fonction :math:`h` approxime au mieux ce qu’il manque pour atteindre l’objectif. Un learning rate égal à 1 fait que la somme des prédictions de chaque fonction :math:`h_m` oscille autour de la vraie valeur, une faible valeur donne l’impression d’une fonction qui converge à petits pas, une grande valeur accroît l’amplitude des oscillations au point d’empêcher l’algorithme de converger. On voit aussi que l’algorithme s’intéresse d’abord aux points où le gradient est le plus fort, donc en principe aux erreurs les plus grandes. Régression quantile ------------------- Dans ce cas, l’erreur quadratique est remplacée par une erreur en valeur absolue. Les résidus dans ce cas sont égaux à -1 ou 1. .. code:: ipython3 alpha = 0.5 model = GradientBoostingRegressor(alpha=alpha, loss='quantile', max_depth=1, learning_rate=0.1) model.fit(X_train, y_train) model01 = GradientBoostingRegressor(alpha=alpha, loss='quantile', max_depth=1, learning_rate=0.01) model01.fit(X_train, y_train) modela = GradientBoostingRegressor(alpha=alpha, loss='quantile', max_depth=1, learning_rate=1.2) modela.fit(X_train, y_train) modelb = GradientBoostingRegressor(alpha=alpha, loss='quantile', max_depth=1, learning_rate=1.99) modelb.fit(X_train, y_train) modelc = GradientBoostingRegressor(alpha=alpha, loss='quantile', max_depth=1, learning_rate=2.01) modelc.fit(X_train, y_train) .. parsed-literal:: GradientBoostingRegressor(alpha=0.5, ccp_alpha=0.0, criterion='friedman_mse', init=None, learning_rate=2.01, loss='quantile', max_depth=1, max_features=None, max_leaf_nodes=None, min_impurity_decrease=0.0, min_impurity_split=None, min_samples_leaf=1, min_samples_split=2, min_weight_fraction_leaf=0.0, n_estimators=100, n_iter_no_change=None, presort='deprecated', random_state=None, subsample=1.0, tol=0.0001, validation_fraction=0.1, verbose=0, warm_start=False) .. code:: ipython3 fig, ax = plt.subplots(1, 5, figsize=(12, 4)) ind = numpy.argsort(X_test, axis=0) for i, mod in enumerate([model, model01, modela, modelb, modelc]): df = DataFrame({'X': X_test[ind].ravel(), 'y': y_test[ind].ravel(), 'y^': mod.predict(X_test)[ind].ravel()}) df.plot(x='X', y='y', kind='scatter', ax=ax[i]) df.plot(x='X', y='y^', kind='line', ax=ax[i], color="r") ax[i].set_title("learning_rate=%1.2f" % mod.learning_rate); .. image:: gradient_boosting_22_0.png Concrètement, le paramètre *max_depth=1* correspond à une simple fonction :math:`f(x) = \mathbf{1\!\!1}_{x > s}` et le modèle final est une somme pondérée de fonctions indicatrices. learning_rate et sur-apprentissage ---------------------------------- .. code:: ipython3 from sklearn.ensemble import RandomForestRegressor from tqdm import tqdm def experiment(models, tries=25): scores = [] for _ in tqdm(range(tries)): rnd = randn(1000) X = random(1000) * 8 - 4 y = X ** 2 - X + rnd * 2 + 150 # X^2 - X + 150 + epsilon X = X.reshape((-1, 1)) X_train, X_test, y_train, y_test = train_test_split(X, y) scs = [] for model in models: model.fit(X_train, y_train) sc = model.score(X_test, y_test) scs.append(sc) scores.append(scs) return scores scores = experiment([ GradientBoostingRegressor(max_depth=1, n_estimators=100), RandomForestRegressor(max_depth=1, n_estimators=100) ]) scores[:3] .. parsed-literal:: 100%|██████████| 25/25 [00:07<00:00, 3.33it/s] .. parsed-literal:: [[0.8694704613325202, 0.6154817789660219], [0.8483182026025287, 0.5448822271424512], [0.8461792771831131, 0.4989444940263401]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="GradientBoostingRegressor") ax.plot([_[1] for _ in scores], label="RandomForestRegressor") ax.set_title("Comparaison pour une somme pondérée de fonctions en escalier") ax.legend(); .. image:: gradient_boosting_26_0.png Ce résultat est attendu car la forêt aléatoire est une moyenne de modèle de régression tous appris dans les mêmes conditions alors que le gradient boosting s’intéresse à l’erreur après la somme des premiers régresseurs. Voyons avec des arbres de décision et non plus des fonctions en escaliers. .. code:: ipython3 from sklearn.tree import DecisionTreeRegressor scores = experiment([ GradientBoostingRegressor(max_depth=5, n_estimators=100), RandomForestRegressor(max_depth=5, n_estimators=100), DecisionTreeRegressor(max_depth=5) ]) .. parsed-literal:: 100%|██████████| 25/25 [00:09<00:00, 2.57it/s] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="GradientBoostingRegressor") ax.plot([_[1] for _ in scores], label="RandomForestRegressor") ax.plot([_[2] for _ in scores], label="DecisionTreeRegressor") ax.set_title("Comparaison pour une somme pondérée d'arbres de décisions") ax.legend(); .. image:: gradient_boosting_29_0.png Le modèle *GradientBoostingRegressor* est clairement moins bon quand le modèle sous-jacent - l’arbre de décision - est performant. On voit que la forêt aléatoire est meilleure qu’un arbre de décision seul. Cela signifie qu’elle généralise mieux et que l’arbre de décision fait du sur apprentissage. De même, le *GradientBoostingRegressor* est plus exposé au sur-apprentissage. .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), GradientBoostingRegressor(max_depth=5, n_estimators=100, learning_rate=0.05), GradientBoostingRegressor(max_depth=5, n_estimators=100, learning_rate=0.1), GradientBoostingRegressor(max_depth=5, n_estimators=100, learning_rate=0.2), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:15<00:00, 1.58it/s] .. parsed-literal:: [[0.8775118863156427, 0.8658450142103171, 0.8606599637847404, 0.8364389493877071], [0.8688453584981832, 0.8702540086892945, 0.8637637833529082, 0.8473494773500022]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor") ax.plot([_[1] for _ in scores], label="GBR(5, lr=0.05)") ax.plot([_[2] for _ in scores], label="GBR(5, lr=0.1)") ax.plot([_[3] for _ in scores], label="GBR(5, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate") ax.legend(); .. image:: gradient_boosting_32_0.png Diminuer *learning_rate* est clairement une façon d’éviter le sur-apprentissage mais les graphes précédents ont montré qu’il fallait plus d’itérations lorsque le learning rate est petit. .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), GradientBoostingRegressor(max_depth=1, n_estimators=100, learning_rate=0.05), GradientBoostingRegressor(max_depth=1, n_estimators=100, learning_rate=0.1), GradientBoostingRegressor(max_depth=1, n_estimators=100, learning_rate=0.2), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:11<00:00, 2.30it/s] .. parsed-literal:: [[0.8729919074479062, 0.8153190929633006, 0.8674320406867211, 0.8718834705539096], [0.8442950556922886, 0.815363804525106, 0.8474302187940742, 0.8444000149837192]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor") ax.plot([_[1] for _ in scores], label="GBR(1, lr=0.05)") ax.plot([_[2] for _ in scores], label="GBR(1, lr=0.1)") ax.plot([_[3] for _ in scores], label="GBR(1, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate et des fonctions en escalier") ax.legend(); .. image:: gradient_boosting_35_0.png Plus le modèle sous-jacent est simple, plus le *learning_rate* peut être élevé car les modèles simples ne font pas de sur-apprentissage. Gradient Boosting avec d’autres librairies ------------------------------------------ Une somme pondérée de régression linéaire reste une regréssion linéaire. Il est impossible de tester ce scénario avec *scikit-learn* puisque seuls les arbres de décisions sont implémentés. Mais il existe d’autres librairies qui implémente le gradient boosting. XGBoost ~~~~~~~ .. code:: ipython3 from xgboost import XGBRegressor .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), XGBRegressor(max_depth=1, n_estimators=100, learning_rate=0.05, objective='reg:squarederror'), XGBRegressor(max_depth=1, n_estimators=100, learning_rate=0.1, objective='reg:squarederror'), XGBRegressor(max_depth=1, n_estimators=100, learning_rate=0.2, objective='reg:squarederror'), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:08<00:00, 2.94it/s] .. parsed-literal:: [[0.8679202687780997, 0.790334034357459, 0.8529726388853197, 0.8635076525988759], [0.8714386434767272, 0.8076555688846012, 0.876320858210121, 0.8795969068127192]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="XGB(1, lr=0.05)") ax.plot([_[2] for _ in scores], label="XGB(1, lr=0.1)") ax.plot([_[3] for _ in scores], label="XGB(1, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des fonctions en escalier " "avec XGBoost") ax.legend(); .. image:: gradient_boosting_41_0.png Les résultats sont sensiblement les mêmes. .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), XGBRegressor(max_depth=5, n_estimators=100, learning_rate=0.05, objective='reg:squarederror'), XGBRegressor(max_depth=5, n_estimators=100, learning_rate=0.1, objective='reg:squarederror'), XGBRegressor(max_depth=5, n_estimators=100, learning_rate=0.2, objective='reg:squarederror'), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:10<00:00, 2.34it/s] .. parsed-literal:: [[0.8850200020052564, 0.8491004361723402, 0.8816335539385363, 0.8760849465925536], [0.8653185803997192, 0.8402218872212899, 0.8683639698989838, 0.8661907635378407]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="XGB(5, lr=0.05)") ax.plot([_[2] for _ in scores], label="XGB(5, lr=0.1)") ax.plot([_[3] for _ in scores], label="XGB(5, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des arbres de décisions " "avec XGBoost") ax.legend(); .. image:: gradient_boosting_44_0.png LightGbm ~~~~~~~~ .. code:: ipython3 from lightgbm import LGBMRegressor .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), LGBMRegressor(max_depth=1, n_estimators=100, learning_rate=0.05), LGBMRegressor(max_depth=1, n_estimators=100, learning_rate=0.1), LGBMRegressor(max_depth=1, n_estimators=100, learning_rate=0.2), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:08<00:00, 3.03it/s] .. parsed-literal:: [[0.8893616908044297, 0.8261124421322801, 0.8817998121916502, 0.8926218231962352], [0.856474322673725, 0.7988728741682812, 0.8481012917344808, 0.8589885895995628]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="LGB(1, lr=0.05)") ax.plot([_[2] for _ in scores], label="LGB(1, lr=0.1)") ax.plot([_[3] for _ in scores], label="LGB(1, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des fonctions en escalier " "avec LightGBM") ax.legend(); .. image:: gradient_boosting_48_0.png .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), LGBMRegressor(max_depth=5, n_estimators=100, learning_rate=0.05), LGBMRegressor(max_depth=5, n_estimators=100, learning_rate=0.1), LGBMRegressor(max_depth=5, n_estimators=100, learning_rate=0.2), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:10<00:00, 2.26it/s] .. parsed-literal:: [[0.8609320085819122, 0.8634839814757147, 0.8597595136945096, 0.8551285081930242], [0.8326411682697042, 0.8292392382894543, 0.8280682654753115, 0.8224006022576665]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="LGB(5, lr=0.05)") ax.plot([_[2] for _ in scores], label="LGB(5, lr=0.1)") ax.plot([_[3] for _ in scores], label="LGB(5, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des arbres de décisions " "avec LightGBM") ax.legend(); .. image:: gradient_boosting_50_0.png `LightGBM `__ paraît moins sensible au *learning_rate* que `XGBoost `__. CatBoost ~~~~~~~~ `CatBoost `__ est une des plus récentes. Elle est sensée être plus efficace pour les catégories ce qui n’est pas le cas ici. .. code:: ipython3 from catboost import CatBoostRegressor .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), CatBoostRegressor(max_depth=1, n_estimators=100, learning_rate=0.05, verbose=False), CatBoostRegressor(max_depth=1, n_estimators=100, learning_rate=0.1, verbose=False), CatBoostRegressor(max_depth=1, n_estimators=100, learning_rate=0.2, verbose=False), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:24<00:00, 1.00it/s] .. parsed-literal:: [[0.8630013062715012, 0.8171496530214813, 0.8705211410285828, 0.8756897741529662], [0.8655349009959259, 0.8082932897705987, 0.8614224979710696, 0.866454702226169]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="CAT(1, lr=0.05)") ax.plot([_[2] for _ in scores], label="CAT(1, lr=0.1)") ax.plot([_[3] for _ in scores], label="CAT(1, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des fonctions en escalier " "avec CatBoost") ax.legend(); .. image:: gradient_boosting_55_0.png .. code:: ipython3 scores = experiment([ RandomForestRegressor(max_depth=5, n_estimators=100), CatBoostRegressor(max_depth=5, n_estimators=100, learning_rate=0.05, verbose=False), CatBoostRegressor(max_depth=5, n_estimators=100, learning_rate=0.1, verbose=False), CatBoostRegressor(max_depth=5, n_estimators=100, learning_rate=0.2, verbose=False), ]) scores[:2] .. parsed-literal:: 100%|██████████| 25/25 [00:31<00:00, 1.27s/it] .. parsed-literal:: [[0.8225527835029143, 0.83387879282829, 0.8336031459553583, 0.8284593124477894], [0.8662884568803738, 0.870941831673826, 0.8731751692649438, 0.8701201310203557]] .. code:: ipython3 fig, ax = plt.subplots(1, 1, figsize=(10, 4)) ax.plot([_[0] for _ in scores], label="RandomForestRegressor(5)") ax.plot([_[1] for _ in scores], label="CAT(5, lr=0.05)") ax.plot([_[2] for _ in scores], label="CAT(5, lr=0.1)") ax.plot([_[3] for _ in scores], label="CAT(5, lr=0.2)") ax.set_title("Comparaison pour différents learning_rate\net des fonctions en escalier " "avec CatBoost") ax.legend(); .. image:: gradient_boosting_57_0.png