Redes Bayesianas e Classificação Naive Bayes

por Frank de Alcantara em 16/08/2026

Redes Bayesianas e Classificação Naive Bayes

No artigo anterior, atualizamos uma hipótese com uma ou duas evidências. O cálculo parecia pequeno porque escondemos o restante do mundo. Se um agente acompanha dezenas de variáveis binárias, a distribuição conjunta completa tem $2^n$ linhas. Com $n=30$, já são $1\,073\,741\,824$ combinações. A aritmética não está errada; a representação está pedindo socorro.

Uma rede bayesiana representa a mesma distribuição por um grafo acíclico dirigido e tabelas de probabilidade locais. O grafo não é decoração. Ele declara quais dependências o modelo conserva e quais independências aceita.

1. A rede como fatoração

Sejam $X_1,\ldots,X_n$ variáveis aleatórias. Uma rede bayesiana contém um nó para cada variável e nenhuma sequência de arestas pode voltar ao nó inicial. Para cada $X_i$, guardamos

\[P(X_i\mid\operatorname{pais}(X_i)).\]

A conjunta é o produto:

\[P(x_1,\ldots,x_n) = \prod_{i=1}^{n} P(x_i\mid\operatorname{pais}(X_i)).\]

Considere a rede clássica do alarme. As variáveis binárias são roubo $B$, terremoto $E$, alarme $A$, João liga $J$ e Maria liga $M$. As arestas são $B\to A$, $E\to A$, $A\to J$ e $A\to M$. A fatoração é

\[P(B,E,A,J,M) =P(B)P(E)P(A\mid B,E)P(J\mid A)P(M\mid A).\]

Uma tabela binária completa teria $2^5-1=31$ parâmetros livres. A rede usa $1$ para $B$, $1$ para $E$, $4$ para $A$, $2$ para $J$ e $2$ para $M$, totalizando $10$. Cada economia corresponde a uma independência assumida.

Exercícios resolvidos

1. Conte os parâmetros da rede do alarme.

Solução:

$1+1+4+2+2=10$, contra $31$ na conjunta completa.

2. Conte uma cadeia binária $A\to B\to C\to D$.

Solução:

A raiz usa $1$ parâmetro e cada outro nó usa $2$: $1+2+2+2=7$.

3. Quando a rede recupera a conjunta completa?

Solução:

Ordene os nós e ligue cada nó a todos os anteriores. A tabela do nó $i$ terá $2^{i-1}$ linhas; a soma dos parâmetros será $2^n-1$.

4. Fatore $A\to C$, $B\to C$, $C\to D$ e $C\to E$.

Solução:

$P(A)P(B)P(C\mid A,B)P(D\mid C)P(E\mid C)$.

5. Qual o efeito de remover um pai binário de um nó binário com $k$ pais?

Solução:

Sua tabela cai de $2^k$ para $2^{k-1}$ parâmetros, redução pela metade.

2. Semântica e independências

A propriedade de Markov local afirma que cada nó é condicionalmente independente de seus não descendentes dados os seus pais. Na rede do alarme, $J$ é independente de $B$ e $E$ quando conhecemos $A$:

\[J\perp\!\!\!\perp\{B,E,M\}\mid A.\]

Três formas de caminho ajudam a ler o grafo. Uma cadeia $X\to Y\to Z$ e uma causa comum $X\leftarrow Y\to Z$ são bloqueadas quando observamos o nó intermediário $Y$. Um colisor $X\to Y\leftarrow Z$ comporta-se ao contrário: o caminho está bloqueado sem observar $Y$ e pode abrir quando observamos $Y$ ou um descendente.

Esse último caso explica o fenômeno chamado explicação por exclusão. Roubo e terremoto são independentes antes de qualquer evidência. Se o alarme toca, ambos se tornam explicações concorrentes. Descobrir um terremoto reduz a necessidade de atribuir o alarme a um roubo.

Uma aresta não prova causalidade. A rede pode ser construída para representar dependências estatísticas sem alegar intervenção. Interpretar toda seta como causa transforma um diagrama útil em uma máquina de inventar histórias.

3. Tabelas de probabilidade condicional

Usaremos os parâmetros tradicionais do exemplo:

\[P(B)=0{,}001,\qquad P(E)=0{,}002.\]

Para o alarme:

$B$ $E$ $P(A\mid B,E)$
verdadeiro verdadeiro 0,95
verdadeiro falso 0,94
falso verdadeiro 0,29
falso falso 0,001

E para as ligações:

\[P(J\mid A)=0{,}90,\quad P(J\mid\neg A)=0{,}05,\] \[P(M\mid A)=0{,}70,\quad P(M\mid\neg A)=0{,}01.\]

As tabelas devem normalizar cada configuração dos pais. Para uma variável binária, guardar $P(A=\text{verdadeiro}\mid B,E)$ basta, pois a probabilidade do valor falso é o complemento.

4. Inferência por enumeração

Queremos $P(B\mid J,M)$. Roubo é a consulta, $J$ e $M$ são evidências, e $E$ e $A$ ficam ocultas. Primeiro calculamos uma quantidade não normalizada:

\[f(b)= \sum_e\sum_a P(b)P(e)P(a\mid b,e)P(J\mid a)P(M\mid a).\]

Depois normalizamos:

\[P(B\mid J,M)=\frac{f(B)}{f(B)+f(\neg B)} \approx 0{,}284172.\]

O roubo continua raro, mas duas chamadas compatíveis com o alarme elevaram a crença de $0{,}1\%$ para $28{,}4\%$.

A enumeração repete subprodutos. A eliminação de variáveis multiplica fatores que envolvem uma variável oculta, soma essa variável e reutiliza o fator resultante. O resultado exato é igual; o custo depende da ordem de eliminação e da largura dos fatores intermediários.

Exercícios resolvidos

1. Calcule a consulta do alarme.

Solução:

Enumerando $E$ e $A$, obtemos $f(B)=0{,}000592243$ e $f(\neg B)=0{,}001491858$; a normalização dá $0{,}284172$.

2. O que significa marginalizar $E$?

Solução:

Somar os termos de $E=\text{verdadeiro}$ e $E=\text{falso}$, removendo a variável do fator.

3. Normalize os valores $0{,}12$ e $0{,}28$.

Solução:

A soma é $0{,}40$; a distribuição normalizada é $(0{,}30,0{,}70)$.

4. Por que a eliminação pode ser melhor?

Solução:

A diferença operacional será:

Método Tratamento dos subprodutos
enumeração ingênua recalcula o mesmo produto em combinações diferentes
eliminação de variáveis calcula, guarda e reutiliza fatores locais

Os dois métodos produzem a mesma inferência exata, mas a eliminação evita trabalho repetido; seu custo final depende da ordem escolhida para eliminar as variáveis.

5. Como tratar evidência parcial $J$ sem $M$?

Solução:

Fixamos $J=\text{verdadeiro}$ e somamos ambos os valores de $M$, além das demais variáveis ocultas.

5. Inferência aproximada

Quando fatores intermediários ficam grandes, podemos aproximar a distribuição com amostras. Na amostragem direta, visitamos os nós em ordem topológica e sorteamos cada valor da tabela condicionada aos pais já sorteados. Ela gera amostras da conjunta, mas pode desperdiçar quase todas se a evidência for rara.

A amostragem por rejeição descarta amostras incompatíveis com a evidência. Se a evidência ocorre uma vez em um milhão, a eficiência também se aproxima de uma em um milhão.

A ponderação por verossimilhança fixa os nós observados e multiplica o peso da amostra pela probabilidade desses valores. Nenhuma amostra é rejeitada, porém pesos podem se concentrar em poucas amostras quando há muita evidência. A amostragem de Gibbs atualiza uma variável não observada por vez condicionada ao seu cobertor de Markov.

Aproximado não significa arbitrário. Precisamos relatar quantidade de amostras, semente, variância entre execuções e alguma medida de erro contra casos pequenos exatos.

6. O classificador Naive Bayes

Seja $Y$ a classe e $F_1,\ldots,F_n$ as características. O modelo Naive Bayes assume que as características são condicionalmente independentes dada a classe:

\[P(F_1,\ldots,F_n\mid Y) =\prod_{i=1}^{n}P(F_i\mid Y).\]

Assim,

\[\hat y = \arg\max_y P(y)\prod_{i=1}^{n}P(f_i\mid y).\]

Para mensagens, uma característica pode indicar se determinada palavra aparece. A hipótese é forte: cartão e crédito certamente não são independentes em textos reais. Ainda assim, o modelo pode classificar bem porque a decisão depende da ordem entre as pontuações, não de cada probabilidade ser perfeitamente calibrada.

Se uma palavra nunca apareceu em uma classe, a estimativa de máxima verossimilhança atribui probabilidade zero e anula todo o produto. A suavização de Laplace para uma característica binária usa

\[P(F_i=1\mid Y=y) = \frac{c_{iy}+1}{N_y+2},\]

em que $c_{iy}$ conta documentos da classe $y$ nos quais a palavra aparece, e $N_y$ conta documentos da classe. Para evitar underflow, somamos logaritmos:

\[\log P(y)+\sum_i\log P(f_i\mid y).\]

Exercícios resolvidos

1. Classifique com pontuações $P(S)=0{,}4$, $P(F_1\mid S)=0{,}8$, $P(F_2\mid S)=0{,}7$ e, para $H$, $0{,}6$, $0{,}2$, $0{,}1$.

Solução:

As massas são $0{,}224$ e $0{,}012$; escolhemos spam.

2. A palavra nunca apareceu em $5$ mensagens de uma classe.

Solução:

Sem suavização, $P=0$; com Laplace binário, $P=(0+1)/(5+2)=1/7$.

3. Converta $0{,}4\cdot0{,}8\cdot0{,}7$.

Solução:

A soma $\log0{,}4+\log0{,}8+\log0{,}7$ representa o mesmo produto sem formar números progressivamente menores.

4. Para uma característica gaussiana com média $0$, desvio $1$ e $x=1$, calcule a densidade.

Solução:

$(2\pi)^{-1/2}e^{-1/2}\approx0{,}241971$.

5. O que ocorre com características duplicadas?

Solução:

A evidência correlacionada é contada duas vezes e pode aumentar indevidamente a confiança, embora a classe vencedora ainda possa estar correta.

7. Avaliação de classificadores

Para uma classe positiva, a matriz de confusão conta verdadeiros positivos $TP$, falsos positivos $FP$, falsos negativos $FN$ e verdadeiros negativos $TN$. Então:

\[\text{acurácia}=\frac{TP+TN}{TP+FP+FN+TN},\] \[\text{precisão}=\frac{TP}{TP+FP},\qquad \text{revocação}=\frac{TP}{TP+FN},\] \[F_1=2\frac{\text{precisão}\cdot\text{revocação}} {\text{precisão}+\text{revocação}}.\]

Um classificador que sempre prevê a classe majoritária alcança $99\%$ de acurácia em um conjunto com $1\%$ de positivos e encontra exatamente zero positivos. Métrica sem distribuição de classes e sem custo de erro é um número bem vestido, apenas isso.

Exercícios resolvidos

1. Use $TP=30$, $FP=10$, $FN=20$, $TN=40$.

Solução:

Acurácia $70\%$, precisão $75\%$, revocação $60\%$ e $F_1=66{,}67\%$.

2. Eleve o limiar da classe positiva.

Solução:

Menos casos passam; em geral, falsos positivos caem e a precisão sobe, enquanto falsos negativos aumentam e a revocação cai.

3. Avalie o classificador majoritário no caso $99/1$.

Solução:

Acurácia $99\%$, mas revocação positiva $0\%$.

4. O que é média macro?

Solução:

Calculamos a métrica separadamente para cada classe e depois fazemos a média aritmética, dando o mesmo peso a classes raras e frequentes.

5. Interprete um ponto ROC $(0{,}1,0{,}8)$.

Solução:

O limiar aceita $10\%$ dos negativos e recupera $80\%$ dos positivos; a AUC resume a probabilidade de um positivo receber pontuação maior que um negativo.

8. Naive Bayes em C++23

O exemplo usa seis palavras e um classificador Bernoulli. Para cada classe, contamos presença por documento, aplicamos Laplace e fazemos a inferência no domínio logarítmico. O conjunto de seis testes é propositalmente pequeno e separável; a acurácia de $100\%$ comprova o programa contra esses seis casos, não o valor do modelo para correio eletrônico real.

#include <array>
#include <cassert>
#include <cmath>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <span>
#include <string_view>

constexpr std::size_t kFeatures = 6;
using Features = std::array<bool, kFeatures>;

struct Example {
    Features features;
    bool spam;
};

struct Metrics {
    int tp{};
    int fp{};
    int fn{};
    int tn{};

    [[nodiscard]] double accuracy() const noexcept {
        return static_cast<double>(tp + tn) / (tp + fp + fn + tn);
    }
    [[nodiscard]] double precision() const noexcept {
        return static_cast<double>(tp) / (tp + fp);
    }
    [[nodiscard]] double recall() const noexcept {
        return static_cast<double>(tp) / (tp + fn);
    }
    [[nodiscard]] double f1() const noexcept {
        const double p = precision();
        const double r = recall();
        return 2.0 * p * r / (p + r);
    }
};

class BernoulliNaiveBayes {
public:
    void fit(const std::span<const Example> examples) {
        std::array<int, 2> class_counts{};
        std::array<std::array<int, kFeatures>, 2> present_counts{};

        for (const auto& example : examples) {
            const std::size_t c = example.spam ? 1uz : 0uz;
            ++class_counts[c];
            for (std::size_t feature = 0; feature < kFeatures; ++feature) {
                present_counts[c][feature] += example.features[feature] ? 1 : 0;
            }
        }

        for (std::size_t c = 0; c < 2; ++c) {
            log_prior_[c] = std::log(
                static_cast<double>(class_counts[c] + 1) /
                static_cast<double>(examples.size() + 2));
            for (std::size_t feature = 0; feature < kFeatures; ++feature) {
                present_probability_[c][feature] =
                    static_cast<double>(present_counts[c][feature] + 1) /
                    static_cast<double>(class_counts[c] + 2);
            }
        }
    }

    [[nodiscard]] bool predict(const Features& features) const {
        std::array<double, 2> scores = log_prior_;
        for (std::size_t c = 0; c < 2; ++c) {
            for (std::size_t feature = 0; feature < kFeatures; ++feature) {
                const double p = present_probability_[c][feature];
                scores[c] += std::log(features[feature] ? p : 1.0 - p);
            }
        }
        return scores[1] > scores[0];
    }

private:
    std::array<double, 2> log_prior_{};
    std::array<std::array<double, kFeatures>, 2> present_probability_{};
};

int main() {
    constexpr std::array<std::string_view, kFeatures> vocabulary{
        "oferta", "grátis", "ganhe", "dinheiro", "reunião", "projeto"};

    constexpr std::array training{
        Example{Features{true, true, true, false, false, false}, true},
        Example{Features{false, true, true, false, false, false}, true},
        Example{Features{true, false, false, true, false, false}, true},
        Example{Features{true, false, true, true, false, false}, true},
        Example{Features{false, false, false, false, true, true}, false},
        Example{Features{false, false, false, false, false, true}, false},
        Example{Features{false, false, false, true, true, true}, false},
        Example{Features{false, false, false, false, true, false}, false},
    };
    constexpr std::array testing{
        Example{Features{true, true, false, false, false, false}, true},
        Example{Features{false, false, true, true, false, false}, true},
        Example{Features{false, true, true, false, false, false}, true},
        Example{Features{false, false, false, false, true, true}, false},
        Example{Features{false, false, false, true, false, true}, false},
        Example{Features{false, false, false, false, true, false}, false},
    };

    BernoulliNaiveBayes model;
    model.fit(training);

    Metrics metrics;
    for (const auto& example : testing) {
        const bool prediction = model.predict(example.features);
        metrics.tp += prediction && example.spam;
        metrics.fp += prediction && !example.spam;
        metrics.fn += !prediction && example.spam;
        metrics.tn += !prediction && !example.spam;
    }

    assert(metrics.tp == 3 && metrics.tn == 3);
    std::cout << "Vocabulário:";
    for (const auto word : vocabulary) {
        std::cout << ' ' << word;
    }
    std::cout << std::fixed << std::setprecision(3)
              << "\nMatriz: TP=" << metrics.tp << " FP=" << metrics.fp
              << " FN=" << metrics.fn << " TN=" << metrics.tn
              << "\nAcurácia=" << metrics.accuracy()
              << " precisão=" << metrics.precision()
              << " revocação=" << metrics.recall()
              << " F1=" << metrics.f1() << '\n';
}

O programa foi compilado com MSVC 19.51, /std:c++latest /permissive- /W4 /EHsc /utf-8 /O2. Produziu $TP=3$, $TN=3$, nenhum erro e as quatro métricas iguais a $1$ no conjunto didático.

No laboratório, fixe João e Maria como evidências e acompanhe a posterior de roubo. Depois ative terremoto e observe a explicação por exclusão.

Conclusão

Redes bayesianas tornam explícito o preço de uma representação compacta: toda tabela removida foi substituída por uma hipótese de independência. Inferência exata soma variáveis ocultas; amostragem troca exatidão por estimativas controláveis; Naive Bayes leva a fatoração ao extremo para aprender um classificador com poucos dados.

No próximo artigo, abandonaremos tabelas de probabilidade definidas à mão e treinaremos uma representação numérica por gradiente, do perceptron ao MLP.

Acrônimos e Abreviações neste artigo

A seguir está a lista de todos os acrônimos e abreviações identificados no texto, organizados em ordem alfabética com o termo original em inglês e a tradução para o português:

Acrônimo / Abreviação Definição em Inglês Tradução em Português
BLAS Basic Linear Algebra Subprograms Subprogramas Básicos de Álgebra Linear
CPU / CPUs Central Processing Unit Unidade Central de Processamento
FLOPs Floating Point Operations Operações de Ponto Flutuante
FP32 32-bit Floating Point Ponto Flutuante de 32 bits
GEMM General Matrix Multiply Multiplicação Geral de Matrizes
GPU Graphics Processing Unit Unidade de Processamento Gráfico
IA Artificial Intelligence Inteligência Artificial
I-JEPA Image Joint-Embedding Predictive Architecture Arquitetura Preditiva de Incorporação Conjunta de Imagem
JEPA Joint-Embedding Predictive Architecture Arquitetura Preditiva de Incorporação Conjunta
KiB Kibibyte Kibibyte
MAE Masked Autoencoder Autocodificador Mascarado
MSE Mean Squared Error Erro Quadrático Médio
MSVC Microsoft Visual C++ Microsoft Visual C++
PCA Principal Component Analysis Análise de Componentes Principais
SIMD Single Instruction, Multiple Data Instrução Única, Múltiplos Dados
SimCLR Simple Framework for Contrastive Learning of Visual Representations Estrutura Simples para Aprendizado Contrastivo de Representações Visuais

Referências

DOMINGOS, P.; PAZZANI, M. On the optimality of the simple Bayesian classifier under zero-one loss. Machine Learning, Dordrecht, v. 29, p. 103–130, 1997. DOI: https://doi.org/10.1023/A:1007413511361. Acesso em: 24 jul. 2026.

LUGER, G. F. Artificial Intelligence: structures and strategies for complex problem solving. 6. ed. Albuquerque: University of New Mexico, 2009. Disponível em: https://www.cs.unm.edu/~luger/ai-final/. Acesso em: 24 jul. 2026.

MICROSOFT. Microsoft C/C++ language conformance by Visual Studio version. Redmond, 2026. Disponível em: https://learn.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?view=msvc-170. Acesso em: 24 jul. 2026.

RUSSELL, S.; NORVIG, P. Artificial Intelligence: a modern approach. 4. ed. Hoboken: Pearson, 2020. Disponível em: https://aima.cs.berkeley.edu/. Acesso em: 24 jul. 2026.

UNIVERSITY OF CALIFORNIA, BERKELEY. Introduction to Artificial Intelligence: Bayes nets. Berkeley, 2024. Disponível em: https://inst.eecs.berkeley.edu/~cs188/textbook/bayes-nets/. Acesso em: 24 jul. 2026.

UNIVERSITY OF CALIFORNIA, BERKELEY. Introduction to Artificial Intelligence: Naive Bayes. Berkeley, 2024. Disponível em: https://inst.eecs.berkeley.edu/~cs188/textbook/ml/naive-bayes.html. Acesso em: 24 jul. 2026.

(Updated: )