<jupyter_start><jupyter_text>2A.ml - Réduction d'une forêt aléatoire - correctionLe 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. Et si on mélangeait les deux ?<jupyter_code>from jyquickhelper import add_notebook_menu
add_notebook_menu()
%matplotlib inline<jupyter_output><empty_output><jupyter_text>DatasetsComme il faut toujours des données, on prend ce jeu [Boston](https://scikit-learn.org/stable/modules/generated/sklearn.datasets.load_boston.html).<jupyter_code>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)<jupyter_output><empty_output><jupyter_text>Une forêt aléatoire<jupyter_code>from sklearn.ensemble import RandomForestRegressor as model_class
clr = model_class()
clr.fit(X_train, y_train)<jupyter_output><empty_output><jupyter_text>Le nombre d'arbres est...<jupyter_code>len(clr.estimators_)
from sklearn.metrics import r2_score
r2_score(y_test, clr.predict(X_test))<jupyter_output><empty_output><jupyter_text>Random Forest = moyenne des prédictionsOn recommence en faisant la moyenne soi-même.<jupyter_code>import numpy
dest = numpy.zeros((X_test.shape[0], len(clr.estimators_)))
estimators = numpy.array(clr.estimators_).ravel()
for i, est in enumerate(estimators):
    pred = est.predict(X_test)
    dest[:, i] = pred

average = numpy.mean(dest, axis=1)
r2_score(y_test, average)<jupyter_output><empty_output><jupyter_text>A priori, c'est la même chose.  Pondérer les arbres à l'aide d'une régression linéaireLa forêt aléatoire est une façon de créer de nouvelles features, 100 exactement qu'on utilise pour caler une régression linéaire.<jupyter_code>from sklearn.linear_model import LinearRegression


def new_features(forest, X):
    dest = numpy.zeros((X.shape[0], len(forest.estimators_)))
    estimators = numpy.array(forest.estimators_).ravel()
    for i, est in enumerate(estimators):
        pred = est.predict(X)
        dest[:, i] = pred
    return dest


X_train_2 = new_features(clr, X_train)
lr = LinearRegression()
lr.fit(X_train_2, y_train)
X_test_2 = new_features(clr, X_test)
r2_score(y_test, lr.predict(X_test_2))<jupyter_output><empty_output><jupyter_text>Un peu moins bien, un peu mieux, le risque d'overfitting est un peu plus grand avec ces nombreuses features car la base d'apprentissage ne contient que 379 observations (regardez ``X_train.shape`` pour vérifier).<jupyter_code>lr.coef_
import matplotlib.pyplot as plt
fig, ax = plt.subplots(1, 1, figsize=(12, 4))
ax.bar(numpy.arange(0, len(lr.coef_)), lr.coef_)
ax.set_title("Coefficients pour chaque arbre calculés avec une régression linéaire");<jupyter_output><empty_output><jupyter_text>Le score est avec une régression linéaire sur les variables initiales est nettement moins élevé.<jupyter_code>lr_raw = LinearRegression()
lr_raw.fit(X_train, y_train)
r2_score(y_test, lr_raw.predict(X_test))<jupyter_output><empty_output><jupyter_text>Sélection d'arbresL'idée est d'utiliser un algorithme de sélection de variables type [Lasso](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.Lasso.html) pour réduire la forêt aléatoire sans perdre en performance. C'est presque le même code.<jupyter_code>from sklearn.linear_model import Lasso

lrs = Lasso(max_iter=10000)
lrs.fit(X_train_2, y_train)
lrs.coef_<jupyter_output><empty_output><jupyter_text>Pas mal de zéros donc pas mal d'arbres non utilisés.<jupyter_code>r2_score(y_test, lrs.predict(X_test_2))<jupyter_output><empty_output><jupyter_text>Pas trop de perte... Ca donne envie d'essayer plusieurs valeur de `alpha`.<jupyter_code>from tqdm import tqdm
alphas = [0.01 * i for i in range(100)] +[1 + 0.1 * i for i in range(100)]
obs = []
for i in tqdm(range(0, len(alphas))):
    alpha = alphas[i]
    lrs = Lasso(max_iter=20000, alpha=alpha)
    lrs.fit(X_train_2, y_train)
    obs.append(dict(
        alpha=alpha,
        null=len(lrs.coef_[lrs.coef_!=0]),
        r2=r2_score(y_test, lrs.predict(X_test_2))
    ))
from pandas import DataFrame
df = DataFrame(obs)
df.tail()
fig, ax = plt.subplots(1, 2, figsize=(12, 4))
df[["alpha", "null"]].set_index("alpha").plot(ax=ax[0], logx=True)
ax[0].set_title("Nombre de coefficients non nulls")
df[["alpha", "r2"]].set_index("alpha").plot(ax=ax[1], logx=True)
ax[1].set_title("r2");<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11505808757819481, 'fraction_numerical': 0.014968722073279714, 'mean_word_length': 6.511744966442953, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 45, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '583305', 'license': 'MIT', 'n_tokens_mistral': 1741, 'n_tokens_neox': 1704, 'n_words': 372, 'path': '_doc/notebooks/td2a_ml/td2a_tree_selection_correction.ipynb', 'repo_name': 'sdpython/ensae_teaching_cs', 'size': '4476'}