Anteriormente discutimos a Regressão Linear tradicional e Ridge. Analogamente, o Lasso (Least Absolute Shrinkage and Selection Operator) é outra técnica de regularização que adiciona uma penalidade L1 à função objetivo, promovendo esparsidade nos coeficientes do modelo.
Conceito Fundamental do Lasso
Primordialmente, o Lasso realiza não apenas a regularização dos coeficientes, mas também seleção de features. Decerto, ao adicionar uma penalidade baseada no valor absoluto dos coeficientes, ele tende a zerar os coeficientes de features menos importantes.
Conforme a documentação do scikit-learn, o Lasso é particularmente útil quando acreditamos que apenas um subconjunto das features é realmente relevante para a previsão. Similarmente ao Ridge, ele ajuda a prevenir overfitting, mas com características distintas.
Formulação Matemática
O objetivo do Lasso é minimizar a seguinte função:
\(\min_{w} \frac{1}{2n}||Xw – y||_2^2 + \alpha||w||_1\)Onde:
- X é a matriz de features
- y é o vetor target
- w são os coeficientes do modelo
- α é o parâmetro de regularização
- ||w||₁ é a norma L1 dos coeficientes
Características Principais do Lasso
Inegavelmente, o Lasso possui propriedades únicas que o distinguem de outras técnicas de regularização:
- Seleção de features: Zera coeficientes de features irrelevantes
- Esparsidade: Produz modelos com poucas features não-zero
- Interpretabilidade: Modelos mais simples e interpretáveis
- Regularização L1: Penalidade baseada no valor absoluto
Comparação: Lasso vs Ridge
Embora ambos sejam técnicas de regularização, existem diferenças fundamentais:
- Lasso (L1): Promove esparsidade, zera coeficientes
- Ridge (L2): Reduz coeficientes, mas não zera
- ElasticNet: Combina L1 e L2
Parâmetros do Lasso
Os principais parâmetros para ajuste no Lasso são:
- alpha: Parâmetro de regularização (α)
- max_iter: Número máximo de iterações
- tol: Tolerância para critério de parada
- selection: Estratégia de seleção de coeficientes
Exemplo Prático: Aplicação do Lasso
Ademais, vejamos um exemplo completo demonstrando o uso do Lasso:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
''' Aplicação do Lasso para Regressão com Seleção de Features Este exemplo demonstra como o Lasso pode ser usado para selecionar features relevantes e evitar overfitting ''' import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_regression from sklearn.linear_model import Lasso, Ridge, LinearRegression from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.preprocessing import StandardScaler from sklearn.metrics import mean_squared_error, r2_score # Gerar dataset com algumas features irrelevantes X, y, true_coef = make_regression(n_samples=1000, n_features=20, n_informative=8, noise=10, coef=True, random_state=42) print("Informações do Dataset:") print(f"Número de amostras: {X.shape[0]}") print(f"Número de features: {X.shape[1]}") print(f"Features informativas: 8") print(f"Coeficientes verdadeiros não-zero: {np.sum(true_coef != 0)}") # Dividir em treino e teste X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42) # Normalizar os dados (importante para regularização) scaler = StandardScaler() X_train_scaled = scaler.fit_transform(X_train) X_test_scaled = scaler.transform(X_test) print(f"\nDimensões: Treino {X_train.shape}, Teste {X_test.shape}") ''' Comparação entre Regressão Linear, Ridge e Lasso Cada método tem características diferentes de regularização ''' models = { 'Linear': LinearRegression(), 'Ridge': Ridge(alpha=1.0), 'Lasso': Lasso(alpha=1.0) } results = {} print("\n--- Comparação de Modelos ---") for name, model in models.items(): # Treinar modelo model.fit(X_train_scaled, y_train) # Fazer previsões y_pred = model.predict(X_test_scaled) # Calcular métricas mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) # Armazenar resultados if hasattr(model, 'coef_'): n_nonzero = np.sum(model.coef_ != 0) results[name] = { 'model': model, 'mse': mse, 'r2': r2, 'n_nonzero': n_nonzero, 'coef': model.coef_ } else: results[name] = { 'model': model, 'mse': mse, 'r2': r2, 'n_nonzero': X.shape[1], 'coef': None } print(f"{name:8} - MSE: {mse:.2f}, R²: {r2:.3f}, Features não-zero: {results[name]['n_nonzero']}") # Otimização do parâmetro alpha para Lasso print("\n--- Otimização do Parâmetro Alpha para Lasso ---") param_grid = { 'alpha': [0.001, 0.01, 0.1, 1, 10, 100, 1000] } grid_search = GridSearchCV(Lasso(max_iter=10000), param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1) grid_search.fit(X_train_scaled, y_train) print(f"Melhor alpha: {grid_search.best_params_['alpha']}") print(f"Melhor MSE na validação: {-grid_search.best_score_:.2f}") # Modelo Lasso otimizado best_lasso = grid_search.best_estimator_ y_pred_best = best_lasso.predict(X_test_scaled) final_mse = mean_squared_error(y_test, y_pred_best) final_r2 = r2_score(y_test, y_pred_best) n_nonzero_best = np.sum(best_lasso.coef_ != 0) print(f"\nLasso Otimizado - MSE: {final_mse:.2f}, R²: {final_r2:.3f}") print(f"Features selecionadas: {n_nonzero_best} de {X.shape[1]}") # Análise dos coeficientes print("\n--- Análise dos Coeficientes ---") print("Comparação entre coeficientes verdadeiros e estimados:") plt.figure(figsize=(15, 10)) # Plot 1: Comparação de coeficientes plt.subplot(2, 2, 1) features = range(len(true_coef)) plt.plot(features, true_coef, 'o-', label='Verdadeiro', linewidth=2, markersize=8) plt.plot(features, results['Linear']['coef'], 's-', label='Linear', alpha=0.7) plt.plot(features, results['Ridge']['coef'], '^-', label='Ridge', alpha=0.7) plt.plot(features, best_lasso.coef_, 'd-', label='Lasso (Otimizado)', alpha=0.7) plt.xlabel('Feature Index') plt.ylabel('Valor do Coeficiente') plt.title('Comparação dos Coeficientes') plt.legend() plt.grid(True, alpha=0.3) # Plot 2: Features selecionadas pelo Lasso plt.subplot(2, 2, 2) lasso_coef_nonzero = best_lasso.coef_ != 0 true_coef_nonzero = true_coef != 0 # Calcular acurácia na seleção de features correct_selection = np.sum(lasso_coef_nonzero == true_coef_nonzero) selection_accuracy = correct_selection / len(true_coef) plt.bar(['Selecionadas', 'Não Selecionadas'], [np.sum(lasso_coef_nonzero), np.sum(~lasso_coef_nonzero)], color=['lightcoral', 'lightblue']) plt.title(f'Seleção de Features pelo Lasso\nAcurácia: {selection_accuracy:.1%}') plt.ylabel('Número de Features') # Plot 3: Performance vs Alpha plt.subplot(2, 2, 3) alphas = param_grid['alpha'] cv_scores = -grid_search.cv_results_['mean_test_score'] plt.semilogx(alphas, cv_scores, 'o-', linewidth=2) plt.xlabel('Alpha') plt.ylabel('MSE') plt.title('Performance vs Parâmetro Alpha') plt.grid(True, alpha=0.3) # Plot 4: Comparação de MSE plt.subplot(2, 2, 4) model_names = list(results.keys()) + ['Lasso Otimizado'] mses = [results[name]['mse'] for name in results.keys()] + [final_mse] plt.bar(model_names, mses, color=['skyblue', 'lightgreen', 'gold', 'lightcoral']) plt.ylabel('MSE') plt.title('Comparação de Erro Quadrático Médio') plt.xticks(rotation=45) plt.tight_layout() plt.show() # Análise detalhada da seleção de features print(f"\n--- Análise Detalhada da Seleção de Features ---") print(f"Coeficientes verdadeiros não-zero: {np.sum(true_coef != 0)}") print(f"Coeficientes Lasso não-zero: {np.sum(best_lasso.coef_ != 0)}") print(f"Features corretamente selecionadas: {np.sum((best_lasso.coef_ != 0) & (true_coef != 0))}") print(f"Features corretamente excluídas: {np.sum((best_lasso.coef_ == 0) & (true_coef == 0))}") print(f"Acurácia total na seleção: {selection_accuracy:.1%}") # Exemplo de interpretação do modelo print(f"\n--- Interpretação do Modelo Lasso ---") print("Features mais importantes (maiores coeficientes em valor absoluto):") important_features = np.argsort(np.abs(best_lasso.coef_))[::-1][:5] for i, feat_idx in enumerate(important_features): if best_lasso.coef_[feat_idx] != 0: print(f"Feature {feat_idx:2d}: coeficiente = {best_lasso.coef_[feat_idx]:.3f}") |
Vantagens e Limitações do Lasso
Embora o Lasso seja poderoso, é importante compreender suas características:
Vantagens
- Seleção automática de features
- Modelos mais interpretáveis
- Bom para high-dimensional data
- Prevenção de overfitting
Limitações
- Pode selecionar apenas uma feature de grupo correlacionado
- Sensível à escala dos dados
- Pode não performar bem quando todas features são relevantes
- Requer ajuste cuidadoso do parâmetro alpha
Casos de Uso Recomendados
O Lasso é particularmente útil em:
- Problemas com muitas features e amostras limitadas
- Quando se deseja interpretabilidade do modelo
- Para seleção de features automática
- Em datasets onde muitas features são irrelevantes
Enfim, o Lasso representa uma ferramenta valiosa no arsenal de machine learning, combinando regularização com seleção de features de maneira eficiente e interpretável.
Referência: https://scikit-learn.org/0.21/modules/linear_model.html#lasso