Hoppa till innehållet
AI-grafen
D· AI-utvecklareklassisk-ml· ca 45 min· grundläggande — ändras sällan· verifierad 2026-09-20

Naive Bayes

Kunna implementera en textklassificerare med Naive Bayes och förklara oberoendeantagandet.

Förkunskaper

Intuition

Naive Bayes svarar på frågan «vilken klass är mest sannolik, givet orden i texten?» med Bayes sats:

P(skra¨ppost∣ord)∝P(skra¨ppost)∏iP(ordi∣skra¨ppost)P(\text{skräppost} \mid \text{ord}) \propto P(\text{skräppost}) \prod_i P(\text{ord}_i \mid \text{skräppost})

Det naiva antagandet är produkten: den förutsätter att orden är oberoende av varandra givet klassen. Det är uppenbart falskt — «maskin» och «inlärning» förekommer tillsammans långt oftare än slumpen säger.

Och ändå fungerar det. Förklaringen är att klassificering bara kräver att rangordningen blir rätt, inte att sannolikheterna är korrekta. Naive Bayes ger ofta helt fel sannolikheter (0,999 när det borde vara 0,8) men rätt klass.

Därför är den fortfarande ett utmärkt första försök på textklassificering: den tränas på sekunder, behöver lite data, och ger en baslinje som mer avancerade metoder måste slå.

Formellt

Två saker måste till för att det ska fungera i praktiken.

1. Laplace-utjämning. Ett ord som aldrig setts i en klass får sannolikheten 0, och hela produkten blir 0 — ett enda okänt ord kan alltså nollställa en klass helt. Lägg till en pseudoräkning α\alpha (oftast 1):

P(w∣c)=antal(w,c)+αantal(c)+α∣V∣P(w \mid c) = \frac{\text{antal}(w, c) + \alpha}{\text{antal}(c) + \alpha|V|}

2. Log-rummet. Produkten av hundratals sannolikheter under 1 underskrider flyttalsprecisionen. Logaritmera:

log⁡P(c∣d)=log⁡P(c)+∑ilog⁡P(wi∣c)\log P(c \mid d) = \log P(c) + \sum_i \log P(w_i \mid c)

Produkten blir en summa, och underflödet försvinner.

Varianter:

VariantDataAnvänds till
Multinomialordfrekvensertextklassificering — standardvalet
Bernoulliord finns/finns intekorta texter, ordförekomst
Gaussiankontinuerliga featuresnumeriska tabeller

När Naive Bayes fortfarande är rätt val:

  • Baslinje innan något tyngre.
  • Mycket lite träningsdata (hundratals dokument).
  • Extremt höga volymer där kostnad per dokument räknas.
  • När modellen måste vara förklarbar — du kan lista de mest utslagsgivande orden direkt ur vikterna.

När den inte är det: när ordföljd spelar roll («inte bra» mot «bra»), när sannolikheterna faktiskt ska användas (de är illa kalibrerade), och när du har mycket data — då vinner en finjusterad transformer.

Bigram löser en del av ordföljdsproblemet billigt: lägg till ordpar som egna features, så fångas «inte bra» som en enhet.

Kod

import math
from collections import Counter, defaultdict

class NaiveBayes:
    def __init__(self, alfa=1.0):
        self.alfa = alfa

    def trana(self, dokument, etiketter):
        self.klasser = sorted(set(etiketter))
        self.ordforrad = {w for d in dokument for w in d.split()}
        self.log_prior, self.antal, self.totalt = {}, {}, {}
        for c in self.klasser:
            docs = [d for d, e in zip(dokument, etiketter) if e == c]
            self.log_prior[c] = math.log(len(docs) / len(dokument))
            self.antal[c] = Counter(w for d in docs for w in d.split())
            self.totalt[c] = sum(self.antal[c].values())
        return self

    def log_p(self, ord_, c):
        V = len(self.ordforrad)
        return math.log((self.antal[c][ord_] + self.alfa) / (self.totalt[c] + self.alfa * V))

    def klassificera(self, text):
        poang = {c: self.log_prior[c] + sum(self.log_p(w, c) for w in text.split()
                                            if w in self.ordforrad)
                 for c in self.klasser}
        return max(poang, key=poang.get), poang

dokument = ["gratis pengar nu", "vinn pengar gratis", "mötet är klockan tre",
            "kan du skicka rapporten", "gratis rapport om pengar"]
etiketter = ["skrap", "skrap", "ok", "ok", "skrap"]

nb = NaiveBayes().trana(dokument, etiketter)
print(nb.klassificera("gratis pengar")[0])              # skrap
print(nb.klassificera("skicka mötet")[0])               # ok

# Vilka ord väger tyngst? — modellen går att förklara
vikt = {w: nb.log_p(w, "skrap") - nb.log_p(w, "ok") for w in nb.ordforrad}
print(sorted(vikt.items(), key=lambda kv: -kv[1])[:3])

# Utan utjämning: ett enda osett ord nollställer klassen
nb0 = NaiveBayes(alfa=0.0).trana(dokument, etiketter)
try:
    nb0.klassificera("mötet pengar")
except ValueError as e:
    print("utan utjämning:", e)          # math domain error → log(0)

Sista blocket är hela skälet till att α\alpha finns: utan den är modellen inte robust mot ett enda ovanligt ord.

Behärskning innebär

  • Implementerar Naive Bayes för text
  • Förklarar oberoendeantagandet och varför det ändå fungerar
  • Använder utjämning och log-rummet

Logga in för att göra övningarna och bygga upp din behärskning.

Källor

Alla källor och licenser