O que são redes bayesianas para classificação?
Redes bayesianas para classificação são modelos gráficos probabilísticos que predizem uma variável alvo discreta. Elas representam dependências entre atributos e a classe usando um grafo acíclico direcionado. Cada nó é uma variável, e arestas indicam influência condicional entre elas. A classe geralmente é um nó especial, frequentemente com pais ou filhos. A classificação é feita calculando P(classe | evidência) via inferência na rede. Diferentemente do Naive Bayes, elas permitem dependências entre atributos. Isso aumenta a acurácia quando atributos são correlacionados. Além disso, redes bayesianas podem lidar com dados faltantes e variáveis latentes. Elas são interpretáveis: cada aresta tem um significado causal ou associativo. Portanto, são usadas em diagnósticos, sistemas especialistas e bioinformática.
Características fundamentais
Redes para classificação possuem três características principais que as definem. Primeiro, a estrutura pode ser aprendida a partir dos dados (aprendizado de estrutura). Segundo, a inferência pode ser exata (para redes pequenas) ou aproximada (MCMC). Terceiro, elas fornecem distribuições de probabilidade sobre as classes, não apenas rótulos. Isso é essencial para decisões com custos assimétricos. A classe pode ser um nó raiz (causa) ou um nó folha (efeito). Quando a classe é raiz, o modelo é gerativo (ex.: Naive Bayes). Quando é folha, é discriminativo (ex.: redes de regressão logística bayesiana).
Vantagens e aplicações típicas
A principal vantagem é a flexibilidade para modelar relações complexas entre atributos. Elas são usadas em classificação de textos, imagens e sinais médicos. Também são aplicadas em sistemas de recomendação e detecção de intrusão. Contudo, o aprendizado de estrutura é computacionalmente caro.
O classificador TAN (Tree-Augmented Naive Bayes) é um exemplo prático. Ele adiciona arestas entre atributos para capturar as correlações mais fortes. A estrutura é aprendida usando árvore de máxima extensão ponderada por informação mútua. Outra abordagem é usar redes bayesianas completas com restrição de treewidth. Isso permite inferência exata com complexidade controlada. Na classificação, a variável alvo pode ter múltiplos estados (ex.: doença, estágio). As redes bayesianas também podem integrar conhecimento de especialistas via estrutura manual. Isso é valioso quando os dados são escassos ou ruidosos. A predição é feita por propagação de evidências para o nó classe. Algoritmos como eliminação de variáveis ou amostragem são usados. A saída probabilística permite calibrar a confiança da classificação. Por exemplo, pode-se rejeitar amostras com baixa probabilidade máxima. Redes bayesianas também suportam aprendizado incremental com novos dados. Assim, elas são ferramentas poderosas para classificação robusta e interpretável.
Um exemplo clássico é a classificação de risco de crédito com variáveis: renda, idade, histórico, e empréstimo (classe). A rede modela que renda e idade influenciam histórico, e histórico influencia o risco. Dadas as evidências, a rede calcula P(risco | dados) para decisão de aprovação.
Enunciado do exemplo clássico
Implemente uma rede bayesiana para classificar se um paciente tem gripe (G) ou resfriado (R) com base em: Febre (F), Tosse (T) e Dor de Cabeça (D). Todas binárias. Relações: G e R influenciam F, T e D de forma independente (Naive Bayes com duas classes). Defina CPTs manualmente. Dados de treino: 50 pacientes com rótulos. Calcule a acurácia em 20 novos pacientes (gerados sinteticamente). Plote a estrutura da rede e a matriz de confusão.
|
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 |
import numpy as np import matplotlib.pyplot as plt import networkx as nx from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay # Definição da rede (Naive Bayes com duas classes) # Classes: 0 = Gripe, 1 = Resfriado (priores) P_G = 0.4 P_R = 0.6 # Probabilidades condicionais: P(Sintoma | Classe) # Febre (F) P_F_dado_G = {0: 0.1, 1: 0.9} # P(F=0|G), P(F=1|G) P_F_dado_R = {0: 0.3, 1: 0.7} # Tosse (T) P_T_dado_G = {0: 0.2, 1: 0.8} P_T_dado_R = {0: 0.5, 1: 0.5} # Dor de Cabeça (D) P_D_dado_G = {0: 0.3, 1: 0.7} P_D_dado_R = {0: 0.4, 1: 0.6} # Função para gerar dados sintéticos def gerar_paciente(classe): if classe == 0: # Gripe F = 1 if np.random.random() < P_F_dado_G[1] else 0 T = 1 if np.random.random() < P_T_dado_G[1] else 0 D = 1 if np.random.random() < P_D_dado_G[1] else 0 else: # Resfriado F = 1 if np.random.random() < P_F_dado_R[1] else 0 T = 1 if np.random.random() < P_T_dado_R[1] else 0 D = 1 if np.random.random() < P_D_dado_R[1] else 0 return np.array([F, T, D]), classe # Gerar treino (50) e teste (20) np.random.seed(123) n_treino = 50 n_teste = 20 dados_treino = [] rotulos_treino = [] for _ in range(n_treino): classe = 0 if np.random.random() < P_G else 1 x, y = gerar_paciente(classe) dados_treino.append(x) rotulos_treino.append(y) dados_treino = np.array(dados_treino) rotulos_treino = np.array(rotulos_treino) dados_teste = [] rotulos_teste = [] for _ in range(n_teste): classe = 0 if np.random.random() < P_G else 1 x, y = gerar_paciente(classe) dados_teste.append(x) rotulos_teste.append(y) dados_teste = np.array(dados_teste) rotulos_teste = np.array(rotulos_teste) # Classificador Naive Bayes (aprendendo as probabilidades dos dados de treino) # Estimar priores priores = np.array([np.mean(rotulos_treino == 0), np.mean(rotulos_treino == 1)]) # Estimar P(sintoma | classe) para cada atributo # Atributos: 0=F, 1=T, 2=D probs = [] for classe in (0,1): dados_classe = dados_treino[rotulos_treino == classe] probs_classe = [] for atributo in range(3): # P(atributo=1 | classe) prob1 = np.mean(dados_classe[:, atributo] == 1) probs_classe.append({0: 1-prob1, 1: prob1}) probs.append(probs_classe) # probs[classe][atributo][valor] def classificar(sintomas): # sintomas: array [F, T, D] posteriores = [] for classe in (0,1): log_prob = np.log(priores[classe]) for atr, valor in enumerate(sintomas): # Suavização para evitar log(0) p = probs[classe][atr][valor] if p == 0: p = 1e-6 log_prob += np.log(p) posteriores.append(log_prob) return 0 if posteriores[0] > posteriores[1] else 1 # Classificar teste predicoes = [classificar(dados_teste[i]) for i in range(n_teste)] acuracia = np.mean(predicoes == rotulos_teste) print(f"Acurácia no teste: {acuracia:.3f}") # Matriz de confusão cm = confusion_matrix(rotulos_teste, predicoes) # Plotar estrutura da rede G = nx.DiGraph() G.add_edges_from([('Classe', 'Febre'), ('Classe', 'Tosse'), ('Classe', 'Dor_Cabeca')]) pos = {'Classe': (1, 1), 'Febre': (0, 0), 'Tosse': (1, 0), 'Dor_Cabeca': (2, 0)} plt.figure(figsize=(12, 5)) plt.subplot(1, 2, 1) nx.draw(G, pos, with_labels=True, node_color='lightgreen', node_size=2500, font_size=10, font_weight='bold', arrowsize=20, edge_color='gray', width=2) plt.title('Rede Bayesiana para Classificação\n(Gripe vs Resfriado)') plt.subplot(1, 2, 2) ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=['Gripe', 'Resfriado']).plot(ax=plt.gca(), cmap='Blues') plt.title(f'Matriz de Confusão (Acurácia = {acuracia:.3f})') plt.tight_layout() plt.show() # Exemplo de classificação de um novo paciente novo = np.array([1, 0, 1]) # Febre=sim, Tosse=não, Dor=sim classe_pred = classificar(novo) print(f"\nNovo paciente (Febre=1, Tosse=0, Dor=1) -> {['Gripe','Resfriado'][classe_pred]}") |
Este código implementa uma rede Naive Bayes para classificação com duas classes. A estrutura mostra a classe como nó raiz influenciando todos os sintomas. A matriz de confusão revela o desempenho do modelo nos dados de teste. O modelo estima probabilidades diretamente dos dados de treino. Para iniciantes, este exemplo demonstra como redes bayesianas resolvem classificação. Redes bayesianas para classificação são, portanto, práticas e interpretáveis.