Imagine que você é um botânico iniciante tentando identificar espécies de íris em um jardim. Você mede cuidadosamente as pétalas e sépalas, mas algumas flores parecem estar no limite entre duas espécies. Em vez de fazer um palpite, você gostaria de saber: “Qual a probabilidade de esta ser uma íris setosa versus virginica?” O Gaussian Process Classifier (GPC) no dataset Iris faz exatamente isso – ele não apenas classifica, mas fornece probabilidades calibradas que refletem o quão confiante é cada identificação, especialmente para aquelas flores que desafiam categorização simples.
Como isso funciona na prática?
O dataset Iris é o “Hello World” da classificação multiclasse, contendo três espécies de íris com quatro medidas cada. Enquanto a maioria dos classificadores fornece apenas um label, o GPC oferece uma abordagem probabilística sofisticada. Ele modela funções latentes separadas para cada classe e usa uma aproximação one-vs-one para problemas multiclasse. Diferentemente de métodos que apenas maximizam acurácia, o GPC captura a incerteza inerente aos dados, mostrando onde as fronteiras entre espécies são nebulosas e onde são bem definidas. Esta nuance é particularmente valiosa em problemas do mundo real onde decisões erradas têm custos.
Mãos na massa: classificando íris com probabilidades
|
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 |
""" Classificação de espécies de Íris usando Gaussian Process Classifier Demonstra classificação multiclasse com quantificação de incerteza """ import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.gaussian_process import GaussianProcessClassifier from sklearn.gaussian_process.kernels import RBF from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler from sklearn.metrics import classification_report, confusion_matrix import seaborn as sns # Carregando o dataset Iris iris = load_iris() X, y = iris.data, iris.target nomes_classes = iris.target_names nomes_caracteristicas = iris.feature_names print("=== DATASET IRIS ===") print(f"Forma dos dados: {X.shape}") print(f"Classes: {list(nomes_classes)}") print(f"Características: {list(nomes_caracteristicas)}") print(f"Distribuição das classes: {np.bincount(y)}") # Pré-processamento: normalização é importante para GPC scaler = StandardScaler() X_normalizado = scaler.fit_transform(X) # Dividindo em treino e teste X_treino, X_teste, y_treino, y_teste = train_test_split( X_normalizado, y, test_size=0.3, random_state=42, stratify=y ) print(f"\nDivisão treino/teste: {X_treino.shape[0]} para treino, {X_teste.shape[0]} para teste") # Criando e treinando o GPC kernel = 1.0 * RBF(length_scale=1.0) gpc = GaussianProcessClassifier( kernel=kernel, random_state=42, n_restarts_optimizer=5 ) print("\nTreinando GPC...") gpc.fit(X_treino, y_treino) print(f"Kernel otimizado: {gpc.kernel_}") # Fazendo previsões probabilísticas y_pred = gpc.predict(X_teste) y_prob = gpc.predict_proba(X_teste) # Avaliando o modelo acuracia = gpc.score(X_teste, y_teste) print(f"\nAcurácia no conjunto de teste: {acuracia:.3f}") # Análise detalhada das previsões print("\n=== ANÁLISE DAS PREVISÕES PROBABILÍSTICAS ===") print("Exemplos de classificações com probabilidades:") # Selecionando alguns casos interessantes para análise indices_analise = [0, 5, 10, 15, 20] # Alguns pontos de teste for idx in indices_analise: probabilidades = y_prob[idx] classe_predita = y_pred[idx] classe_real = y_teste[idx] print(f"\nFlor {idx+1}:") print(f" Classe real: {nomes_classes[classe_real]}") print(f" Classe prevista: {nomes_classes[classe_predita]}") print(f" Probabilidades: {dict(zip(nomes_classes, probabilidades))}") confianca = np.max(probabilidades) classe_mais_provavel = np.argmax(probabilidades) print(f" Confiança: {confianca:.3f}") print(f" Status: {'✓ CORRETO' if classe_predita == classe_real else '✗ ERRADO'}") # Identificando casos de alta incerteza incertezas = 1 - np.max(y_prob, axis=1) casos_incertos = incertezas > 0.3 # Limite arbitrário para alta incerteza print(f"\nCasos com alta incerteza (>30%): {np.sum(casos_incertos)} flores") if np.any(casos_incertos): print("Estas flores estão próximas das fronteiras entre espécies:") for idx in np.where(casos_incertos)[0][:3]: # Mostra os 3 primeiros probs = y_prob[idx] print(f" Flor {idx}: {dict(zip(nomes_classes, probs))}") # Visualização das fronteiras de decisão (em 2D para visualização) def visualizar_fronteiras_2d(): """Visualiza fronteiras de decisão usando as 2 características mais importantes""" # Usando comprimento da pétala e largura da pétala (as mais discriminativas) X_2d = X_normalizado[:, [2, 3]] # petal length, petal width # Treinando GPC apenas com 2 características para visualização gpc_2d = GaussianProcessClassifier(kernel=kernel, random_state=42) gpc_2d.fit(X_2d, y) # Criando grid para visualização x_min, x_max = X_2d[:, 0].min() - 1, X_2d[:, 0].max() + 1 y_min, y_max = X_2d[:, 1].min() - 1, X_2d[:, 1].max() + 1 xx, yy = np.meshgrid(np.linspace(x_min, x_max, 100), np.linspace(y_min, y_max, 100)) # Previsões no grid Z = gpc_2d.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) # Probabilidades no grid Z_prob = gpc_2d.predict_proba(np.c_[xx.ravel(), yy.ravel()]) Z_confidence = np.max(Z_prob, axis=1).reshape(xx.shape) Z_uncertainty = 1 - Z_confidence # Plot fig, axes = plt.subplots(1, 3, figsize=(18, 5)) # Plot 1: Fronteiras de decisão contour1 = axes[0].contourf(xx, yy, Z, alpha=0.6, cmap='Set3') scatter1 = axes[0].scatter(X_2d[:, 0], X_2d[:, 1], c=y, cmap='Set3', edgecolors='black', s=50) axes[0].set_xlabel('Comprimento da Pétala (normalizado)') axes[0].set_ylabel('Largura da Pétala (normalizado)') axes[0].set_title('Fronteiras de Decisão do GPC\nDataset Iris') plt.colorbar(scatter1, ax=axes[0]) # Plot 2: Confiança das previsões contour2 = axes[1].contourf(xx, yy, Z_confidence, levels=20, alpha=0.6, cmap='viridis') axes[1].scatter(X_2d[:, 0], X_2d[:, 1], c=y, cmap='Set3', edgecolors='black', s=50) axes[1].set_xlabel('Comprimento da Pétala (normalizado)') axes[1].set_ylabel('Largura da Pétala (normalizado)') axes[1].set_title('Mapa de Confiança do GPC') plt.colorbar(contour2, ax=axes[1]) # Plot 3: Incerteza contour3 = axes[2].contourf(xx, yy, Z_uncertainty, levels=20, alpha=0.6, cmap='hot_r') axes[2].scatter(X_2d[:, 0], X_2d[:, 1], c=y, cmap='Set3', edgecolors='black', s=50) axes[2].set_xlabel('Comprimento da Pétala (normalizado)') axes[2].set_ylabel('Largura da Pétala (normalizado)') axes[2].set_title('Mapa de Incerteza do GPC\n(Áreas de fronteira)') plt.colorbar(contour3, ax=axes[2]) plt.tight_layout() plt.show() visualizar_fronteiras_2d() # Matriz de confusão print("\n=== MATRIZ DE CONFUSÃO ===") cm = confusion_matrix(y_teste, y_pred) plt.figure(figsize=(8, 6)) sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=nomes_classes, yticklabels=nomes_classes) plt.title('Matriz de Confusão - GPC no Dataset Iris') plt.ylabel('Classe Real') plt.xlabel('Classe Prevista') plt.show() print("\nRelatório de classificação:") print(classification_report(y_teste, y_pred, target_names=nomes_classes)) |
Os detalhes que fazem diferença
O GPC no dataset Iris revela insights importantes sobre a natureza probabilística da classificação. A espécie setosa é facilmente separável das outras, resultando em probabilidades próximas de 1.0 quando corretamente classificada. Contudo, as espécies versicolor e virginica se sobrepõem significativamente, criando regiões de alta incerteza onde o GPC honestamente fornece probabilidades mais balanceadas. Esta transparência é valiosa em aplicações reais onde saber o “quão certo” o modelo está pode ser tão importante quanto a classificação em si. A normalização dos dados é particularmente crucial para o GPC, pois características em escalas diferentes podem distorcer as medidas de similaridade do kernel.
- Normalização obrigatória: Características em escalas diferentes prejudicam o kernel RBF
- Incerteza informativa: Áreas de alta incerteza correspondem a regiões de sobreposição real entre classes
- Abordagem one-vs-one: O GPC usa esta estratégia para problemas multiclasse
- Interpretabilidade: Probabilidades refletem a estrutura subjacente dos dados
Perguntas que os iniciantes fazem
Você deve estar se perguntando: “Por que usar GPC no Iris se outros métodos mais simples também funcionam?” Excelente questão! Enquanto métodos como KNN ou árvores de decisão podem ter acurácia similar, o GPC fornece probabilidades calibradas que são valiosas para aplicações onde você precisa entender não apenas o “o quê” mas o “quão confiante”. Uma confusão comum é pensar que alta incerteza significa que o modelo é ruim – na verdade, ela indica honestidade sobre limites do conhecimento. Outra dúvida frequente: “Como o GPC lida com três classes?” Ele treina classificadores binários para cada par de classes e combina os resultados.
Para onde ir agora?
Experimente o GPC em outros datasets de classificação multiclasse e observe como as probabilidades se comportam em diferentes estruturas de dados. Tente diferentes kernels e observe como afetam as fronteiras de decisão. Use as informações de incerteza para identificar onde coletar mais dados. O momento “aha!” acontece quando você percebe que a incerteza quantificada pelo GPC não é um bug, mas uma feature valiosa que reflete a complexidade inerente dos dados reais.
Assuntos relacionados
Para aprofundar seu entendimento, estude:
- Classificação multiclasse: estratégias one-vs-one e one-vs-rest
- Normalização de dados: importância para métodos baseados em distância
- Análise discriminante: fundamentos teóricos da separação entre classes
- Calibração de probabilidades: como avaliar se probabilidades são realistas
- Visualização de dados multidimensionais: técnicas para entender estruturas complexas