Regularização L1 e Seleção de Features
Analogamente à Regressão de Ridge, o Laço (Lasso) constitui outra técnica fundamental de regularização em modelos lineares. Ademais, enquanto a Ridge utiliza penalização L2, o Lasso emprega penalização L1, o que confere propriedades únicas e particularmente úteis para seleção de features.
Fundamentação Matemática do Lasso
Conforme especificado na documentação do scikit-learn, o Lasso resolve o seguinte problema de otimização:
\(\min_{w} \frac{1}{2n} ||X w – y||_2^2 + \alpha ||w||_1\)Primordialmente, a diferença crucial reside no termo de penalização \(\alpha ||w||_1\), que utiliza a norma L1 em vez da norma L2. Certamente, esta mudança aparentemente sutil produz comportamentos radicalmente diferentes.
Características Distintivas do Lasso
- Seleção de features: Capaz de definir coeficientes exatamente para zero
- Esparsidade: Produz vetores de coeficientes esparsos
- Interpretabilidade: Modelos mais simples e interpretáveis
- Regularização L1: Penalização baseada na soma dos valores absolutos
Comparação: Lasso vs Ridge
Enquanto a Ridge regression apenas reduz a magnitude dos coeficientes, o Lasso pode eliminá-los completamente. Similarmente a um processo de seleção natural, apenas as features mais importantes sobrevivem no modelo final.
Exemplo Prático com 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 |
import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import Lasso, Ridge from sklearn.datasets import make_regression print("=" * 60) print("DEMONSTRAÇÃO PRÁTICA - REGRESSÃO LASSO COM LEGENDAS") print("=" * 60) # Gerar dados com features redundantes X, y = make_regression(n_samples=100, n_features=6, n_informative=3, noise=0.5, random_state=42) print(f"Dimensões: X {X.shape}, y {y.shape}") print(f"Features informativas geradas: 3 de 6") # Configurar parâmetros de regularização n_alphas = 200 alphas = np.logspace(-3, 1, n_alphas) # Armazenar resultados lasso_coefs = [] ridge_coefs = [] for alpha in alphas: # Lasso regression lasso = Lasso(alpha=alpha, max_iter=10000) lasso.fit(X, y) lasso_coefs.append(lasso.coef_) # Ridge regression para comparação ridge = Ridge(alpha=alpha) ridge.fit(X, y) ridge_coefs.append(ridge.coef_) lasso_coefs = np.array(lasso_coefs) ridge_coefs = np.array(ridge_coefs) # Visualização comparativa com legendas plt.figure(figsize=(16, 8)) # Gráfico Lasso com legendas plt.subplot(1, 2, 1) cores = ['red', 'blue', 'green', 'orange', 'purple', 'brown'] for i in range(lasso_coefs.shape[1]): plt.plot(alphas, lasso_coefs[:, i], color=cores[i], linewidth=2, label=f'Feature {i+1}') plt.xscale('log') plt.xlabel('Alpha (escala logarítmica)', fontsize=12) plt.ylabel('Valor do Coeficiente', fontsize=12) plt.title('LASSO: Regularização L1\n(Convergência para Zero Exato)', fontsize=14, fontweight='bold') plt.axhline(y=0, color='black', linestyle='-', alpha=0.3) plt.grid(True, alpha=0.3) # Adicionar legenda fora do gráfico para melhor visualização plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., fontsize=10) # Gráfico Ridge com legendas plt.subplot(1, 2, 2) for i in range(ridge_coefs.shape[1]): plt.plot(alphas, ridge_coefs[:, i], color=cores[i], linewidth=2, label=f'Feature {i+1}') plt.xscale('log') plt.xlabel('Alpha (escala logarítmica)', fontsize=12) plt.ylabel('Valor do Coeficiente', fontsize=12) plt.title('RIDGE: Regularização L2\n(Convergência Suave para Zero)', fontsize=14, fontweight='bold') plt.axhline(y=0, color='black', linestyle='-', alpha=0.3) plt.grid(True, alpha=0.3) # Adicionar legenda fora do gráfico plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left', borderaxespad=0., fontsize=10) plt.tight_layout() plt.show() # 💡 ANÁLISE DETALHADA COM DESTAQUE PARA FEATURES SELECIONADAS print("\n" + "=" * 50) print("ANÁLISE DE SELEÇÃO DE FEATURES") print("=" * 50) # Testar diferentes valores de alpha alpha_valores = [0.001, 0.01, 0.1, 0.5, 1.0] for alpha in alpha_valores: lasso_model = Lasso(alpha=alpha, max_iter=10000) lasso_model.fit(X, y) features_nao_nulas = np.where(lasso_model.coef_ != 0)[0] features_nulas = np.where(lasso_model.coef_ == 0)[0] print(f"\nAlpha = {alpha:.3f}:") print(f" Features selecionadas: {features_nao_nulas + 1}") print(f" Features eliminadas: {features_nulas + 1}") print(f" Coeficientes: {lasso_model.coef_}") # 🎯 VISUALIZAÇÃO ALTERNATIVA: GRÁFICO DE BARRAS PARA COEFICIENTES plt.figure(figsize=(14, 6)) # Selecionar um alpha específico para demonstração alpha_demo = 0.1 lasso_demo = Lasso(alpha=alpha_demo, max_iter=10000) lasso_demo.fit(X, y) ridge_demo = Ridge(alpha=alpha_demo) ridge_demo.fit(X, y) # Gráfico de barras comparativo plt.subplot(1, 2, 1) indices = np.arange(len(lasso_demo.coef_)) largura = 0.35 plt.bar(indices - largura/2, lasso_demo.coef_, largura, label='Lasso', alpha=0.7, color='red') plt.bar(indices + largura/2, ridge_demo.coef_, largura, label='Ridge', alpha=0.7, color='blue') plt.xlabel('Features') plt.ylabel('Valor do Coeficiente') plt.title(f'Comparação Lasso vs Ridge (alpha={alpha_demo})') plt.xticks(indices, [f'F{i+1}' for i in range(len(lasso_demo.coef_))]) plt.legend() plt.grid(True, alpha=0.3) # Gráfico de sparsidade plt.subplot(1, 2, 2) coeficientes_nao_nulos = (lasso_demo.coef_ != 0).astype(int) plt.bar(range(len(coeficientes_nao_nulos)), coeficientes_nao_nulos, color=['red' if x == 0 else 'green' for x in coeficientes_nao_nulos]) plt.xlabel('Features') plt.ylabel('Selecionada (1) / Eliminada (0)') plt.title('Sparsidade do Lasso: Features Selecionadas') plt.xticks(range(len(coeficientes_nao_nulos)), [f'F{i+1}' for i in range(len(coeficientes_nao_nulos))]) plt.tight_layout() plt.show() print("\n" + "=" * 50) print("INTERPRETAÇÃO DOS RESULTADOS") print("=" * 50) print(""" 🔍 OBSERVAÇÕES: 1. LASSO (L1): • Coeficientes podem se tornar EXATAMENTE zero • Efeito de seleção de features • Modelos esparsos e interpretáveis 2. RIDGE (L2): • Coeficientes apenas se aproximam de zero • Sem eliminação completa de features • Convergência mais suave 3. LEGENDAS: • Agora cada feature é claramente identificada • Cores consistentes facilitam a comparação • Posicionamento evita sobreposição """) |
Vantagens Práticas do Lasso
Inegavelmente, a capacidade de produzir modelos esparsos confere ao Lasso vantagens significativas em cenários específicos. Afinal, em problemas com muitas features, a seleção automática simplifica consideravelmente a interpretação do modelo.
Aplicações Típicas do Lasso
- Seleção de variáveis: Identificar features mais relevantes
- Modelos interpretáveis: Construir modelos com poucas variáveis
- Redução de dimensionalidade: Eliminar features redundantes
- Regularização agressiva: Controle rigoroso de overfitting
Considerações de Implementação
Embora poderoso, o Lasso requer alguns cuidados na implementação. Ocasionalmente, pode ser necessário aumentar o número máximo de iterações (max_iter) para garantir convergência, especialmente com muitos dados.
Contudo, o scikit-learn oferece implementações otimizadas como LassoCV que automatizam a seleção do melhor parâmetro alpha através de validação cruzada.
Geometria da Penalização L1
A propriedade de sparsidade do Lasso decorre da geometria da norma L1. Similarmente a um contorno com “cantos”, a interseção entre a função de erro e a restrição L1 tende a ocorrer nos eixos, onde alguns coeficientes são exatamente zero.
Conclusão
Portanto, o Lasso representa uma ferramenta valiosa no arsenal do cientista de dados. Analogamente a um filtro de precisão, ele é capaz de separar sinais importantes de ruído estatístico.
Enfim, a compreensão das diferenças entre Lasso e Ridge é essencial para selecionar a técnica apropriada para cada problema. Inclusive, em muitos casos práticos, uma combinação de ambas através do Elastic Net pode oferecer o melhor dos dois mundos.