Naive Bayes
Kunna implementera en textklassificerare med Naive Bayes och förklara oberoendeantagandet.
Förkunskaper
- DBayes satskrävs
- DTextförbehandlingkrävs
Intuition
Naive Bayes svarar på frågan «vilken klass är mest sannolik, givet orden i texten?» med Bayes sats:
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 (oftast 1):
2. Log-rummet. Produkten av hundratals sannolikheter under 1 underskrider flyttalsprecisionen. Logaritmera:
Produkten blir en summa, och underflödet försvinner.
Varianter:
| Variant | Data | Används till |
|---|---|---|
| Multinomial | ordfrekvenser | textklassificering — standardvalet |
| Bernoulli | ord finns/finns inte | korta texter, ordförekomst |
| Gaussian | kontinuerliga features | numeriska 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 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
- scikit-learn User Guide (BSD-3) — BSD-3-Clause
- Jurafsky & Martin — Speech and Language Processing (3:e utkastet) — fri att läsa online (författarnas utkast)
- Dive into Deep Learning (CC BY-SA 4.0) — CC BY-SA 4.0