Scikit-learn ne prend effectivement pas en charge la régression par étapes. En effet, ce qu'on appelle communément la «régression par étapes» est un algorithme basé sur les valeurs p des coefficients de régression linéaire, et scikit-learn évite délibérément l'approche par inférence de l'apprentissage par modèle (test de signification, etc.). De plus, la pure méthode MLS n'est que l'un des nombreux algorithmes de régression et, du point de vue de l'acquisition de connaissances scientifiques, ce n'est ni très important, ni l'un des meilleurs.
Il y a cependant quelques conseils à donner à ceux qui ont encore besoin d'un bon moyen de sélectionner des fonctionnalités avec des modèles linéaires:
- Utilisez des modèles intrinsèquement clairs comme
ElasticNet
ou Lasso
.
- Normalisez vos fonctionnalités avec
StandardScaler
, puis commandez-les simplement par model.coef_
. Pour des covariables parfaitement indépendantes, cela équivaut à un tri par valeurs p. La classe le sklearn.feature_selection.RFE
fera pour vous et RFECV
évaluera même le nombre optimal de fonctionnalités.
- R2
statsmodels
- Effectuez une sélection en avant ou en arrière par force brute afin de maximiser votre métrique préférée lors de la validation croisée (cela peut prendre un temps approximativement quadratique en nombre de covariables). Un
mlxtend
package compatible avec scikit-learn prend en charge cette approche pour tout estimateur et toute métrique.
- Si vous souhaitez toujours une régression progressive vanille, il est plus facile de la baser
statsmodels
, car ce package calcule les valeurs p pour vous. Une sélection de base en avant-arrière pourrait ressembler à ceci:
`` `
from sklearn.datasets import load_boston
import pandas as pd
import numpy as np
import statsmodels.api as sm
data = load_boston()
X = pd.DataFrame(data.data, columns=data.feature_names)
y = data.target
def stepwise_selection(X, y,
initial_list=[],
threshold_in=0.01,
threshold_out = 0.05,
verbose=True):
""" Perform a forward-backward feature selection
based on p-value from statsmodels.api.OLS
Arguments:
X - pandas.DataFrame with candidate features
y - list-like with the target
initial_list - list of features to start with (column names of X)
threshold_in - include a feature if its p-value < threshold_in
threshold_out - exclude a feature if its p-value > threshold_out
verbose - whether to print the sequence of inclusions and exclusions
Returns: list of selected features
Always set threshold_in < threshold_out to avoid infinite looping.
See https://en.wikipedia.org/wiki/Stepwise_regression for the details
"""
included = list(initial_list)
while True:
changed=False
# forward step
excluded = list(set(X.columns)-set(included))
new_pval = pd.Series(index=excluded)
for new_column in excluded:
model = sm.OLS(y, sm.add_constant(pd.DataFrame(X[included+[new_column]]))).fit()
new_pval[new_column] = model.pvalues[new_column]
best_pval = new_pval.min()
if best_pval < threshold_in:
best_feature = new_pval.argmin()
included.append(best_feature)
changed=True
if verbose:
print('Add {:30} with p-value {:.6}'.format(best_feature, best_pval))
# backward step
model = sm.OLS(y, sm.add_constant(pd.DataFrame(X[included]))).fit()
# use all coefs except intercept
pvalues = model.pvalues.iloc[1:]
worst_pval = pvalues.max() # null if pvalues is empty
if worst_pval > threshold_out:
changed=True
worst_feature = pvalues.argmax()
included.remove(worst_feature)
if verbose:
print('Drop {:30} with p-value {:.6}'.format(worst_feature, worst_pval))
if not changed:
break
return included
result = stepwise_selection(X, y)
print('resulting features:')
print(result)
Cet exemple afficherait le résultat suivant:
Add LSTAT with p-value 5.0811e-88
Add RM with p-value 3.47226e-27
Add PTRATIO with p-value 1.64466e-14
Add DIS with p-value 1.66847e-05
Add NOX with p-value 5.48815e-08
Add CHAS with p-value 0.000265473
Add B with p-value 0.000771946
Add ZN with p-value 0.00465162
resulting features:
['LSTAT', 'RM', 'PTRATIO', 'DIS', 'NOX', 'CHAS', 'B', 'ZN']