O que são redes bayesianas com variáveis discretas?
Redes bayesianas com variáveis discretas são modelos probabilísticos onde cada nó assume valores categóricos finitos. Esses valores podem ser binários (sim/não), ordinais (baixo/médio/alto) ou nominais (cor/forma). Cada nó possui uma tabela de probabilidade condicional (CPT) que lista todas as combinações possíveis. Por exemplo, um nó com 3 pais binários terá 2³ = 8 entradas na sua CPT. A distribuição conjunta é o produto de todas as CPTs, como nas redes contínuas. Contudo, o raciocínio é feito por contagem e soma, não por integrais. Isso torna a inferência exata viável para redes de tamanho moderado. Variáveis discretas são naturais em diagnósticos, classificação e sistemas especialistas. Elas também são mais fáceis de interpretar por seres humanos não-técnicos.
Características fundamentais
Essas redes possuem três características marcantes que as distinguem. Primeiro, as CPTs são matrizes de probabilidade que somam 1 para cada linha. Segundo, a independência condicional é testada por testes qui-quadrado ou mutual information. Terceiro, a inferência pode ser feita por eliminação de variáveis, que é exata. A aprendizagem de parâmetros é feita por máxima verossimilhança (contagens) ou suavização de Laplace. A suavização evita probabilidades zero para combinações não observadas nos dados. Além disso, a estrutura pode ser aprendida por busca gulosa usando BIC ou AIC. Redes discretas são amplamente suportadas por bibliotecas como pgmpy e bnlearn.
Vantagens e aplicações típicas
A principal vantagem é a simplicidade computacional e interpretabilidade. Elas são usadas em sistemas de suporte à decisão médica (ex.: diagnóstico de gripe x covid). Também são aplicadas em filtros de spam, sistemas de recomendação e mineração de dados. Outra vantagem é a facilidade de incorporar conhecimento de especialistas via CPTs. Contudo, o número de parâmetros cresce exponencialmente com o número de pais. Para lidar com isso, usa-se estruturas esparsas ou árvores de decisão nas CPTs.
O tratamento de variáveis discretas é mais antigo e consolidado na literatura. Modelos como o classificador Naive Bayes são um caso especial com um único nó pai. Redes mais complexas podem ter múltiplas camadas de dependência entre variáveis. A inferência por eliminação de variáveis elimina nós não observados por soma. Isso reduz o problema a consultas condicionais simples de ser calculadas. Para redes grandes (dezenas de nós), usa-se amostragem de Gibbs ou MCMC. A amostragem gera aproximações, mas é escalável e fácil de implementar. A suavização de Laplace adiciona pseudocontagens para evitar overfitting. Isso é especialmente importante quando os dados são escassos. Redes bayesianas discretas também podem modelar séries temporais com cadeias de Markov. Nesse caso, cada nó tem arestas do tempo t-1 para t. Elas são usadas em previsão de demanda e análise de séries climáticas. A estrutura pode ser visualizada como um diagrama de influência. Assim, redes discretas são uma ferramenta madura e amplamente aplicada.
Um exemplo clássico é o problema do “Carro Não Liga” com variáveis: Bateria (B), Gasolina (G), Partida (P), e Motor (M). Todas são binárias (boa/ruim, cheia/vazia, etc.). A rede calcula a probabilidade de cada causa dado que o motor não liga. Isso auxilia o mecânico a diagnosticar a falha de forma estruturada.
Enunciado do exemplo clássico
Implemente uma rede bayesiana discreta para o diagnóstico de um motor de carro. Variáveis: Bateria (B: 0=ruim, 1=boa), Gasolina (G: 0=vazia, 1=cheia), Partida (P: 0=não funciona, 1=funciona), Motor (M: 0=não liga, 1=liga). Relações: B e G influenciam P; P influencia M. Defina CPTs manualmente com valores razoáveis. Calcule P(B=0 | M=0) e P(G=0 | M=0) usando inferência exata. Plote a rede graficamente e uma barra com as probabilidades posteriores.
|
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 |
import numpy as np import matplotlib.pyplot as plt import networkx as nx # Definição da rede com variáveis discretas (binárias) # Priores: P(B) e P(G) P_B = {0: 0.1, 1: 0.9} # 10% bateria ruim P_G = {0: 0.15, 1: 0.85} # 15% gasolina vazia # Condicional: P(P | B, G) # ordem: B,G -> P P_P_dado_BG = { (0,0,0): 0.01, (0,0,1): 0.99, # B=0,G=0, P=0 e P=1 (0,1,0): 0.05, (0,1,1): 0.95, # B=0,G=1 (1,0,0): 0.10, (1,0,1): 0.90, # B=1,G=0 (1,1,0): 0.02, (1,1,1): 0.98 # B=1,G=1 } # Condicional: P(M | P) P_M_dado_P = { (0,0): 0.01, (0,1): 0.99, # P=0, M=0 e M=1 (1,0): 0.05, (1,1): 0.95 # P=1, M=0 e M=1 } # Função de inferência por enumeração (exata) def inferir_discreto(variavel, evidencia): # variáveis: B, G, P, M # evidencia: dict {var: valor} prob_total = {0: 0.0, 1: 0.0} for b in (0,1): for g in (0,1): for p in (0,1): for m in (0,1): # Verificar evidência ok = True if 'B' in evidencia and evidencia['B'] != b: ok = False if 'G' in evidencia and evidencia['G'] != g: ok = False if 'P' in evidencia and evidencia['P'] != p: ok = False if 'M' in evidencia and evidencia['M'] != m: ok = False if not ok: continue # Probabilidade conjunta p = P_B[b] * P_G[g] * P_P_dado_BG[(b,g,p)] * P_M_dado_P[(p,m)] if variavel == 'B': prob_total[b] += p elif variavel == 'G': prob_total[g] += p elif variavel == 'P': prob_total[p] += p elif variavel == 'M': prob_total[m] += p soma = sum(prob_total.values()) if soma > 0: prob_total[0] /= soma prob_total[1] /= soma return prob_total # Calcular P(B=0 | M=0) - bateria ruim dado que motor não liga P_B_dado_M0 = inferir_discreto('B', {'M': 0}) print(f"P(B=0 | M=0) = {P_B_dado_M0[0]:.4f}") print(f"P(B=1 | M=0) = {P_B_dado_M0[1]:.4f}") # Calcular P(G=0 | M=0) - gasolina vazia dado que motor não liga P_G_dado_M0 = inferir_discreto('G', {'M': 0}) print(f"P(G=0 | M=0) = {P_G_dado_M0[0]:.4f}") print(f"P(G=1 | M=0) = {P_G_dado_M0[1]:.4f}") # Plotar estrutura da rede G = nx.DiGraph() G.add_edges_from([('B', 'P'), ('G', 'P'), ('P', 'M')]) pos = {'B': (0, 1), 'G': (0, 0), 'P': (1, 0.5), 'M': (2, 0.5)} 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=12, font_weight='bold', arrowsize=20, edge_color='gray', width=2) plt.title('Rede Bayesiana Discreta - Diagnóstico do Motor') plt.subplot(1, 2, 2) # Gráfico de barras para probabilidades posteriores categorias = ['B=0 (ruim)', 'B=1 (boa)', 'G=0 (vazia)', 'G=1 (cheia)'] valores = [P_B_dado_M0[0], P_B_dado_M0[1], P_G_dado_M0[0], P_G_dado_M0[1]] cores = ['red', 'green', 'orange', 'blue'] bars = plt.bar(categorias, valores, color=cores, edgecolor='black') plt.ylim(0, 1) plt.ylabel('Probabilidade dado M=0 (motor não liga)') plt.title('Probabilidades Posteriores das Causas') for bar, val in zip(bars, valores): plt.text(bar.get_x() + bar.get_width()/2, bar.get_height() + 0.02, f'{val:.2f}', ha='center', va='bottom', fontweight='bold') plt.grid(axis='y', linestyle='--', alpha=0.7) plt.tight_layout() plt.show() |
Este código implementa uma rede discreta com inferência por enumeração. A estrutura do grafo mostra a relação causal entre bateria, gasolina, partida e motor. As barras de probabilidade revelam que a bateria ruim é a causa mais provável. A gasolina vazia tem uma probabilidade menor, mas ainda significativa. Para iniciantes, este exemplo demonstra o poder diagnóstico das redes discretas. Elas são, portanto, ferramentas essenciais para sistemas baseados em regras.