2A.ml - Pipeline pour un réduction d’une forêt aléatoire - énoncé

Links: notebook, html, PDF, python, slides, GitHub

Le modèle Lasso permet de sélectionner des variables, une forêt aléatoire produit une prédiction comme étant la moyenne d’arbres de régression. Cet aspect a été abordé dans le notebook Reduction d’une forêt aléatoire. On cherche à automatiser le processus.

from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline

Datasets

Comme il faut toujours des données, on prend ce jeu Boston.

from sklearn.datasets import load_boston
data = load_boston()
X, y = data.data, data.target
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y)

Forêt aléatoire suivi de Lasso

La méthode consiste à apprendre une forêt aléatoire puis à effectuer d’une régression sur chacun des estimateurs.

import numpy
from sklearn.ensemble import RandomForestRegressor
from sklearn.linear_model import Lasso

# Apprentissage d'une forêt aléatoire
clr = RandomForestRegressor()
clr.fit(X_train, y_train)

# Récupération de la prédiction de chaque arbre
X_train_2 = numpy.zeros((X_train.shape[0], len(clr.estimators_)))
estimators = numpy.array(clr.estimators_).ravel()
for i, est in enumerate(estimators):
    pred = est.predict(X_train)
    X_train_2[:, i] = pred

# Apprentissage d'une régression Lasso
lrs = Lasso(max_iter=10000)
lrs.fit(X_train_2, y_train)
lrs.coef_
array([0.03143403, 0.        , 0.        , 0.00283899, 0.01930698,
       0.        , 0.01955177, 0.        , 0.04229851, 0.06075116,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.        , 0.        , 0.        ,
       0.01863875, 0.        , 0.        , 0.        , 0.        ,
       0.11662719, 0.        , 0.02069583, 0.        , 0.00838764,
       0.01036738, 0.        , 0.04139117, 0.01097605, 0.        ,
       0.        , 0.01087936, 0.00461544, 0.0194921 , 0.        ,
       0.        , 0.        , 0.        , 0.00723295, 0.        ,
       0.01038525, 0.        , 0.        , 0.02801566, 0.        ,
       0.02543287, 0.        , 0.02637795, 0.        , 0.        ,
       0.        , 0.01926008, 0.        , 0.0809758 , 0.        ,
       0.        , 0.        , 0.        , 0.01117441, 0.        ,
       0.01695082, 0.        , 0.        , 0.        , 0.00630067,
       0.        , 0.        , 0.        , 0.02544154, 0.        ,
       0.02391149, 0.0516138 , 0.0248029 , 0.        , 0.01746167,
       0.        , 0.        , 0.04544503, 0.02975665, 0.        ,
       0.03906748, 0.01736363, 0.        , 0.        , 0.        ,
       0.        , 0.        , 0.01108544, 0.03801782, 0.03433332,
       0.        , 0.        , 0.        , 0.        , 0.        ])

Nous avons réussi à reproduire le processus dans son ensemble. Pas toujours simple de se souvenir de toutes les étapes, c’est pourquoi il est plus simple de compiler l’ensemble dans un pipeline.

Exercice 1 : Premier pipeline

Peut-être trouverez-vous tout de suite un pipeline qui fonctionne. La partie difficile est la partie qui produit le vecteur des sorties de chaque arbre de régression. La première piste que j’ai explorée est un FunctionTransformer.

Exercice 2 : Second pipeline

La première idée de marche pas vraiment… On décide alors de déguiser la forêt aléatoire en un transformeur.

class RandomForestRegressorAsTransformer:

    def __init__(self, **kwargs):
        self.rf = RandomForestRegressor(**kwargs)

    def fit(self, X, y):
        # ...
        return self

    def transform(self, X):
        # ...
        # return les prédiction de chaque arbre
        pass

# Tout ça pour écrire ce qui suit...
trrf = RandomForestRegressorAsTransformer()
trrf.fit(X_train, y_train)
trrf.transform(X_train)

Il reste à écrire le pipeline correspondant à la séquence d’apprentissage décrit quelque part dans ce notebook.

from sklearn.pipeline import Pipeline

pipe = Pipeline(steps=[
    ('name', 'passthrough'),
    # ...
])

pipe.fit(X_train, y_train)
Pipeline(memory=None, steps=[('name', 'passthrough')], verbose=False)

Exercice 3 : GridSearchCV

Comme l’ensemble des traitements sont maintenant dans un seul pipeline que scikit-learn considère comme un modèle comme les autres, on peut rechercher les meilleurs hyper-paramètres du modèle, comme le nombre d’arbres initial, le paramètre alpha, la profondeur des arbres… Tout ça avec la classe GridSearchCV.

Vous devriez tomber sur un message disant que la classe RandomForestRegressorAsTransformer a besoin de la méthode set_params… Un indice : def set_params(self, **params): self.rf.set_params(**params).

Exercice 4 : nombre de coefficients non nuls

Il ne reste plus qu’à trouver le nombre de coefficients non nuls du meilleur modèle, donc le nombre d’arbres conservés par le modèle.