Analogamente a um sistema de decisão que calcula probabilidades, a Regressão Logística constitui um dos algoritmos mais populares para problemas de classificação. Ademais, conforme documentado no scikit-learn, esta técnica modela a probabilidade de pertencimento a classes através de uma função logística.
Fundamentação Matemática da Regressão Logística
Primordialmente, a Regressão Logística utiliza a função sigmoide para transformar saídas lineares em probabilidades. Certamente, a função sigmoide é definida como:
\(\sigma(z) = \frac{1}{1 + e^{-z}}\)Onde \(z = w^T x + b\) representa a combinação linear das features. Similarmente a um limiar de decisão, valores acima de 0.5 indicam uma classe, enquanto valores abaixo indicam a outra.
Função de Custo e Otimização
A Regressão Logística minimiza a entropia cruzada (cross-entropy), que mede a dissimilaridade entre distribuições de probabilidade:
\(J(w) = -\frac{1}{N} \sum_{i=1}^{N} [y_i \log(\hat{y_i}) + (1-y_i) \log(1-\hat{y_i})]\)Esta função é convexa, garantindo convergência para um mínimo global através de algoritmos como gradient descent.
Tipos de Regressão Logística no Scikit-Learn
Classificação Binária
Para problemas com duas classes, o scikit-learn oferece LogisticRegression com parâmetro multi_class=’ovr’. Decerto, esta abordagem é adequada para a maioria dos problemas de classificação binária.
Classificação Multiclasse
Para problemas com múltiplas classes, duas estratégias estão disponíveis:
- One-vs-Rest (OvR): Treina um classificador binário para cada classe
- Multinomial: Treina um único classificador para todas as classes
Regularização
Embora seja um classificador, a Regressão Logística suporta regularização L1 e L2 para prevenir overfitting. Contudo, a escolha do parâmetro C (inverso da força de regularização) é crucial para o desempenho.
Exemplo Prático: Classificação Binária e Multiclasse
|
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 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 |
import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LogisticRegression from sklearn.datasets import make_classification, make_blobs from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report, confusion_matrix, accuracy_score from sklearn.preprocessing import StandardScaler print("=" * 60) print("REGRESSÃO LOGÍSTICA - CLASSIFICAÇÃO BINÁRIA E MULTICLASSE") print("=" * 60) # 1. CLASSIFICAÇÃO BINÁRIA print("\n" + "=" * 50) print("1. CLASSIFICAÇÃO BINÁRIA") print("=" * 50) # Gerar dados para classificação binária X_bin, y_bin = make_classification( n_samples=1000, n_features=2, n_redundant=0, n_informative=2, n_clusters_per_class=1, random_state=42 ) print(f"Dados binários: {X_bin.shape[0]} amostras, {X_bin.shape[1]} features") print(f"Distribuição das classes: {np.unique(y_bin, return_counts=True)}") # Dividir e normalizar dados X_bin_train, X_bin_test, y_bin_train, y_bin_test = train_test_split( X_bin, y_bin, test_size=0.3, random_state=42 ) scaler_bin = StandardScaler() X_bin_train_scaled = scaler_bin.fit_transform(X_bin_train) X_bin_test_scaled = scaler_bin.transform(X_bin_test) # Treinar modelo de regressão logística binária log_reg_bin = LogisticRegression( penalty='l2', # Regularização L2 C=1.0, # Inverso da força de regularização solver='lbfgs', # Algoritmo de otimização max_iter=1000, random_state=42 ) log_reg_bin.fit(X_bin_train_scaled, y_bin_train) # Previsões e métricas y_bin_pred = log_reg_bin.predict(X_bin_test_scaled) y_bin_prob = log_reg_bin.predict_proba(X_bin_test_scaled) accuracy_bin = accuracy_score(y_bin_test, y_bin_pred) print(f"\nAcurácia (binária): {accuracy_bin:.4f}") print(f"Coeficientes: {log_reg_bin.coef_}") print(f"Intercepto: {log_reg_bin.intercept_}") # 2. CLASSIFICAÇÃO MULTICLASSE print("\n" + "=" * 50) print("2. CLASSIFICAÇÃO MULTICLASSE") print("=" * 50) # Gerar dados para classificação multiclasse X_multi, y_multi = make_blobs( n_samples=1500, centers=3, n_features=2, cluster_std=1.5, random_state=42 ) print(f"Dados multiclasse: {X_multi.shape[0]} amostras, {X_multi.shape[1]} features") print(f"Número de classes: {len(np.unique(y_multi))}") print(f"Distribuição das classes: {np.unique(y_multi, return_counts=True)}") # Dividir e normalizar dados X_multi_train, X_multi_test, y_multi_train, y_multi_test = train_test_split( X_multi, y_multi, test_size=0.3, random_state=42 ) scaler_multi = StandardScaler() X_multi_train_scaled = scaler_multi.fit_transform(X_multi_train) X_multi_test_scaled = scaler_multi.transform(X_multi_test) # Treinar modelo de regressão logística multiclasse log_reg_multi = LogisticRegression( penalty='l2', C=1.0, solver='lbfgs', multi_class='multinomial', # Classificação multinomial max_iter=1000, random_state=42 ) log_reg_multi.fit(X_multi_train_scaled, y_multi_train) # Previsões e métricas y_multi_pred = log_reg_multi.predict(X_multi_test_scaled) y_multi_prob = log_reg_multi.predict_proba(X_multi_test_scaled) accuracy_multi = accuracy_score(y_multi_test, y_multi_pred) print(f"\nAcurácia (multiclasse): {accuracy_multi:.4f}") print(f"Coeficientes shape: {log_reg_multi.coef_.shape}") print(f"Intercepto shape: {log_reg_multi.intercept_.shape}") # Visualização dos resultados plt.figure(figsize=(15, 10)) # Gráfico 1: Classificação Binária - Dados e Fronteira de Decisão plt.subplot(2, 3, 1) plt.scatter(X_bin_train_scaled[:, 0], X_bin_train_scaled[:, 1], c=y_bin_train, cmap='bwr', alpha=0.6, edgecolors='k') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.title('Dados de Treino - Classificação Binária') plt.colorbar() # Gráfico 2: Classificação Binária - Fronteira de Decisão plt.subplot(2, 3, 2) xx, yy = np.meshgrid( np.linspace(X_bin_train_scaled[:, 0].min(), X_bin_train_scaled[:, 0].max(), 100), np.linspace(X_bin_train_scaled[:, 1].min(), X_bin_train_scaled[:, 1].max(), 100) ) Z = log_reg_bin.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.3, cmap='bwr') plt.scatter(X_bin_test_scaled[:, 0], X_bin_test_scaled[:, 1], c=y_bin_test, cmap='bwr', alpha=0.8, edgecolors='k') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.title('Fronteira de Decisão - Classificação Binária') # Gráfico 3: Probabilidades - Classificação Binária plt.subplot(2, 3, 3) plt.scatter(X_bin_test_scaled[:, 0], y_bin_prob[:, 1], c=y_bin_test, cmap='bwr') plt.xlabel('Feature 1') plt.ylabel('Probabilidade Classe 1') plt.title('Probabilidades Previstas - Binária') plt.colorbar() # Gráfico 4: Classificação Multiclasse - Dados plt.subplot(2, 3, 4) plt.scatter(X_multi_train_scaled[:, 0], X_multi_train_scaled[:, 1], c=y_multi_train, cmap='viridis', alpha=0.6, edgecolors='k') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.title('Dados de Treino - Multiclasse') plt.colorbar() # Gráfico 5: Classificação Multiclasse - Fronteiras de Decisão plt.subplot(2, 3, 5) xx, yy = np.meshgrid( np.linspace(X_multi_train_scaled[:, 0].min(), X_multi_train_scaled[:, 0].max(), 100), np.linspace(X_multi_train_scaled[:, 1].min(), X_multi_train_scaled[:, 1].max(), 100) ) Z = log_reg_multi.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.3, cmap='viridis') plt.scatter(X_multi_test_scaled[:, 0], X_multi_test_scaled[:, 1], c=y_multi_test, cmap='viridis', alpha=0.8, edgecolors='k') plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.title('Fronteiras de Decisão - Multiclasse') # Gráfico 6: Probabilidades - Classificação Multiclasse plt.subplot(2, 3, 6) prob_max = np.max(y_multi_prob, axis=1) plt.scatter(X_multi_test_scaled[:, 0], prob_max, c=y_multi_test, cmap='viridis') plt.xlabel('Feature 1') plt.ylabel('Probabilidade Máxima') plt.title('Confiança das Previsões - Multiclasse') plt.colorbar() plt.tight_layout() plt.show() # 💡 ANÁLISE DETALHADA DOS RESULTADOS print("\n" + "=" * 50) print("ANÁLISE DETALHADA DOS MODELOS") print("=" * 50) # Relatório de classificação para binária print("\nRELATÓRIO DE CLASSIFICAÇÃO - BINÁRIA:") print(classification_report(y_bin_test, y_bin_pred)) # Relatório de classificação para multiclasse print("\nRELATÓRIO DE CLASSIFICAÇÃO - MULTICLASSE:") print(classification_report(y_multi_test, y_multi_pred)) # Matriz de confusão para multiclasse print("\nMATRIZ DE CONFUSÃO - MULTICLASSE:") print(confusion_matrix(y_multi_test, y_multi_pred)) # Análise dos coeficientes print(f"\nANÁLISE DOS COEFICIENTES - MULTICLASSE:") for i, coef_class in enumerate(log_reg_multi.coef_): print(f"Classe {i}: coef = [{coef_class[0]:.3f}, {coef_class[1]:.3f}]") # Comparação de estratégias multiclasse print(f"\nCOMPARAÇÃO DE ESTRATÉGIAS MULTICLASSE:") strategies = ['ovr', 'multinomial'] accuracies = [] for strategy in strategies: log_reg_strategy = LogisticRegression( penalty='l2', C=1.0, solver='lbfgs', multi_class=strategy, max_iter=1000, random_state=42 ) log_reg_strategy.fit(X_multi_train_scaled, y_multi_train) y_pred_strategy = log_reg_strategy.predict(X_multi_test_scaled) acc = accuracy_score(y_multi_test, y_pred_strategy) accuracies.append(acc) print(f"Estratégia {strategy}: Acurácia = {acc:.4f}") print(f"\nRECOMENDAÇÕES PRÁTICAS:") print("1. Para problemas binários: multi_class='ovr'") print("2. Para problemas multiclasse: testar 'ovr' vs 'multinomial'") print("3. Normalizar features para melhor performance") print("4. Ajustar parâmetro C para controlar regularização") |
Interpretação dos Resultados
Inegavelmente, a Regressão Logística demonstra excelente performance tanto em problemas binários quanto multiclasse. Afinal, as fronteiras de decisão lineares são claramente visíveis nos gráficos, mostrando a capacidade do modelo em separar classes de forma eficaz.
Vantagens da Regressão Logística
- Interpretabilidade: Coeficientes indicam a importância das features
- Probabilidades: Fornece probabilidades de pertencimento às classes
- Eficiência: Computacionalmente eficiente mesmo com muitas features
- Versatilidade: Aplicável a problemas binários e multiclasse
Considerações Práticas
Embora seja um algoritmo robusto, a Regressão Logística assume linearidade entre features e o logito. Ocasionalmente, em problemas com relações não-lineares complexas, outros algoritmos como Random Forest ou SVM podem performar melhor.
Contudo, para a maioria dos problemas de classificação onde a interpretabilidade é importante, a Regressão Logística permanece como uma excelente escolha inicial.
Conclusão
Portanto, a Regressão Logística representa uma ferramenta fundamental no arsenal do cientista de dados. Analogamente a um diagnóstico médico baseado em probabilidades, este algoritmo combina poder preditivo com interpretabilidade.
Enfim, o domínio da Regressão Logística e suas variações permite abordar uma ampla gama de problemas de classificação, desde diagnósticos médicos até sistemas de recomendação, sempre com a capacidade de explicar as decisões do modelo.