O Scikit-learn de fato não suporta regressão gradual. Isso porque o que é comumente conhecido como 'regressão stepwise' é um algoritmo baseado em valores-p dos coeficientes de regressão linear, e o scikit-learn evita deliberadamente a abordagem inferencial do modelo de aprendizagem (teste de significância, etc.). Além disso, o OLS puro é apenas um dos numerosos algoritmos de regressão e, do ponto de vista do aprendizado do scikit, não é muito importante nem um dos melhores.
No entanto, existem alguns conselhos para quem ainda precisa de um bom caminho para a seleção de recursos com modelos lineares:
- Use modelos inerentemente esparsos como
ElasticNet
ou Lasso
.
- Normalize seus recursos com
StandardScaler
e, em seguida, encomende-os apenas por model.coef_
. Para covariáveis perfeitamente independentes, é equivalente à classificação por valores-p. A turma sklearn.feature_selection.RFE
fará isso por você e RFECV
até avaliará o número ideal de recursos.
- R2
statsmodels
- Faça a seleção de força bruta para frente ou para trás para maximizar sua métrica favorita na validação cruzada (isso pode levar aproximadamente tempo quadrático no número de covariáveis). Um
mlxtend
pacote compatível com o scikit-learn suporta essa abordagem para qualquer estimador e qualquer métrica.
- Se você ainda deseja a regressão passo a passo de baunilha, é mais fácil basear isso
statsmodels
, pois este pacote calcula valores de p para você. Uma seleção básica para frente e para trás pode ser assim:
`` ``
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)
Este exemplo imprimiria a seguinte saída:
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']