Faza 02 · lecția 14
Naive Bayes
Scopul lecției: Ipoteza „naivă” este greșită și totuși funcționează. Aceasta este frumusețea ei.
Versiunea curentă AlexBred.com: primele 100 de lecții ale programului în limba română.
Cuprinsul lecției
- Obiective de învățare
- Problema
- Conceptul
- Teorema lui Bayes (recapitulare rapidă)
- Ipoteza naivă de independență
- De ce funcționează totuși
- Matematica pas cu pas
- Trei variante
- Când se folosește fiecare variantă
- Netezirea Laplace
- Calculul în spațiul logaritmic
- Naive Bayes în raport cu regresia logistică
- Pipeline de clasificare
- Construiți
- MultinomialNB
- GaussianNB
- Demonstrație: clasificarea textului
- Demonstrație: caracteristici continue
- Viteza predicției
- Folosiți
- TF-IDF cu Naive Bayes
- BernoulliNB pentru texte scurte
- Calibrarea probabilităților NB
- Capcane frecvente
- Livrați
- Când eșuează Naive Bayes
- Exerciții
- Termeni-cheie
- Lecturi suplimentare
Ipoteza „naivă” este greșită și totuși funcționează. Aceasta este frumusețea ei.
Tip: Construire Limbaj: Python Cerințe preliminare: Faza 2, lecțiile 01–07 (clasificare, teorema lui Bayes) Durată: ~75 de minute
Obiective de învățare
- Implementați de la zero Multinomial Naive Bayes cu netezire Laplace pentru clasificarea textului
- Explicați de ce ipoteza naivă de independență este greșită matematic, dar produce în practică ierarhizări corecte ale claselor
- Comparați variantele Multinomial, Bernoulli și Gaussian Naive Bayes și selectați-o pe cea potrivită pentru un anumit tip de caracteristici
- Evaluați Naive Bayes în raport cu regresia logistică pe date rare, cu dimensionalitate mare, și explicați compromisul deplasare–varianță aflat în joc
Problema
Trebuie să clasificați text. E-mailuri în spam sau non-spam. Recenzii ale clienților în pozitive sau negative. Tichete de asistență pe categorii. Aveți mii de caracteristici (câte una pentru fiecare cuvânt) și date de antrenare limitate.
Majoritatea clasificatorilor se blochează aici. Regresia logistică are nevoie de suficiente eșantioane pentru a estima fiabil mii de ponderi. Arborii de decizie împart datele după câte un cuvânt și supraînvață puternic. KNN în 10.000 de dimensiuni nu are sens, deoarece fiecare punct este la aceeași distanță față de toate celelalte.
Naive Bayes face față acestei situații. El pornește de la o ipoteză greșită matematic (că fiecare caracteristică este independentă de toate celelalte condiționat de clasă) și totuși depășește modele „mai inteligente” în clasificarea textului, mai ales cu seturi de antrenare mici. Se antrenează într-o singură trecere prin date. Se extinde la milioane de caracteristici. Produce estimări ale probabilităților (deși acestea sunt adesea slab calibrate din cauza ipotezei de independență).
Înțelegerea motivului pentru care o ipoteză greșită duce la predicții bune vă învață ceva fundamental despre învățarea automată: cel mai bun model nu este cel mai corect, ci acela cu cel mai bun compromis deplasare–varianță pentru datele dumneavoastră.
Notă tehnică a traducerii: Aceste comparații sunt euristice, nu proprietăți universale. Regresia logistică regularizată este ea însăși un reper puternic pentru text rar cu dimensionalitate mare, iar performanța arborilor și KNN depinde de reprezentare, metrică și reglare. Naive Bayes nu depășește garantat modelele discriminative, iar timpul de antrenare pe milioane de caracteristici depinde de caracterul rar al matricei, implementare și hardware.
Conceptul
Teorema lui Bayes (recapitulare rapidă)
Teorema lui Bayes inversează probabilitățile condiționate:
P(clasă | caracteristici) = P(caracteristici | clasă) * P(clasă) / P(caracteristici)
Dorim P(clasă | caracteristici) — probabilitatea ca un document să aparțină unei clase, date fiind cuvintele din el. O putem calcula din:
P(caracteristici | clasă)— verosimilitatea observării acestor cuvinte în documentele din clasa respectivăP(clasă)— probabilitatea a priori a clasei (cât de frecvent este spamul în general?)P(caracteristici)— evidența, aceeași pentru toate clasele, astfel încât o putem ignora în comparație
Câștigă clasa cu cea mai mare valoare P(clasă | caracteristici).
Ipoteza naivă de independență
Calcularea exactă a P(caracteristici | clasă) necesită estimarea probabilității comune a tuturor caracteristicilor luate împreună. Cu un vocabular de 10.000 de cuvinte, ar trebui să estimați o distribuție peste 2^10.000 de combinații posibile. Imposibil.
Ipoteza naivă: fiecare caracteristică este independentă condiționat de clasă.
P(w1, w2, ..., wn | clasă) = P(w1 | clasă) * P(w2 | clasă) * ... * P(wn | clasă)
În locul unei singure distribuții comune imposibile, estimați n distribuții simple, câte una pentru fiecare caracteristică. Fiecare necesită doar un număr de apariții.
Această ipoteză este evident greșită. Cuvintele „machine” și „learning” nu sunt independente în niciun document. Clasificatorul nu are însă nevoie de estimări corecte ale probabilității. Are nevoie de ierarhizări corecte — care clasă are probabilitatea cea mai mare. Ipoteza de independență introduce erori sistematice, dar acestea afectează în mod similar toate clasele, astfel încât ierarhizarea rămâne corectă.
Notă tehnică a traducerii: Independența condiționată este de obicei nerealistă pentru limbaj, dar nu este „greșită” pentru orice distribuție. Numărul
2^10.000descrie vectori binari de prezență/absență; pentru numărări multinomiale spațiul are altă structură. Mai important, erorile nu afectează obligatoriu clasele în mod similar: dependențele pot schimba chiar clasa cu scor maxim. Rezultatele de optimalitate pentru pierderea 0–1 cer condiții precise, nu garantează conservarea ierarhizării în general.
De ce funcționează totuși
Trei motive:
-
Ierarhizare în loc de calibrare. Clasificarea necesită doar ca prima clasă din ierarhie să fie corectă. Chiar dacă P(spam) = 0,99999 atunci când probabilitatea reală este 0,7, clasificatorul alege tot corect spam. Nu avem nevoie de probabilități corecte. Avem nevoie de câștigătorul corect.
-
Deplasare mare, varianță mică. Ipoteza de independență este o presupunere a priori puternică. Ea constrânge mult modelul, ceea ce previne supraînvățarea. Cu date de antrenare limitate, un model ușor greșit, dar stabil, depășește un model corect teoretic, dar foarte instabil. Acesta este compromisul deplasare–varianță în acțiune.
-
Redundanța caracteristicilor se anulează. Caracteristicile corelate oferă dovezi redundante. Clasificatorul numără aceste dovezi de două ori, dar le numără de două ori și pentru clasa corectă. Dacă „machine” și „learning” apar întotdeauna împreună, ambele oferă dovezi pentru clasa „tech”. NB le numără de două ori, dar le numără de două ori pentru clasa corectă.
Un al patrulea motiv, de natură practică: Naive Bayes este extrem de rapid. Antrenarea constă într-o singură trecere prin date pentru numărarea frecvențelor. Predicția este o înmulțire de matrice. Puteți antrena pe un milion de documente în câteva secunde. Această viteză vă permite să iterați mai repede, să încercați mai multe seturi de caracteristici și să rulați mai multe experimente decât cu modele mai lente.
Notă tehnică a traducerii: Cele trei explicații sunt intuiții, nu garanții. Caracteristicile corelate pot supraevalua repetat aceeași dovadă și pot deteriora atât calibrarea, cât și clasificarea; efectul nu trebuie să se anuleze. În plus, afirmația despre „câteva secunde” depinde de vectorizare, reprezentarea rară, lungimea documentelor și platforma de calcul.
Matematica pas cu pas
Să urmărim un exemplu concret. Presupunem că avem două clase: spam și non-spam. Vocabularul are trei cuvinte: „free”, „money”, „meeting”.
Date de antrenare:
- E-mailurile spam menționează „free” de 80 de ori, „money” de 60 de ori și „meeting” de 10 ori (150 de cuvinte în total)
- E-mailurile non-spam menționează „free” de 5 ori, „money” de 10 ori și „meeting” de 100 de ori (115 cuvinte în total)
- 40% dintre e-mailuri sunt spam, iar 60% sunt non-spam
Cu netezire Laplace (alpha=1):
P(free | spam) = (80 + 1) / (150 + 3) = 81/153 = 0.529
P(money | spam) = (60 + 1) / (150 + 3) = 61/153 = 0.399
P(meeting | spam) = (10 + 1) / (150 + 3) = 11/153 = 0.072
P(free | non-spam) = (5 + 1) / (115 + 3) = 6/118 = 0.051
P(money | non-spam) = (10 + 1) / (115 + 3) = 11/118 = 0.093
P(meeting | non-spam) = (100 + 1) / (115 + 3) = 101/118 = 0.856
Noul e-mail conține: „free” (de 2 ori), „money” (o dată), „meeting” (de 0 ori).
log P(spam | e-mail) = log(0.4) + 2*log(0.529) + 1*log(0.399) + 0*log(0.072)
= -0.916 + 2*(-0.637) + (-0.919) + 0
= -3.109
log P(non-spam | e-mail) = log(0.6) + 2*log(0.051) + 1*log(0.093) + 0*log(0.856)
= -0.511 + 2*(-2.976) + (-2.375) + 0
= -8.838
Spam câștigă cu o diferență mare. Cuvântul „free” apărut de două ori este o dovadă puternică pentru spam. Observați că absența cuvântului „meeting” contribuie cu zero la ambele sume logaritmice (0 * log(P)) — în Multinomial NB, cuvintele absente nu au efect. Bernoulli NB este varianta care modelează explicit absența cuvintelor.
Notă tehnică a traducerii: Valorile
-3.109și-8.838sunt scoruri logaritmice nenormalizate,log P(clasă) + log P(e-mail | clasă). Ele omit termenul comunlog P(e-mail)și sunt suficiente pentruargmax, dar nu sunt literalmente valorile normalizatelog P(clasă | e-mail)afișate în formule.
Trei variante
Naive Bayes are trei variante. Fiecare modelează diferit P(caracteristică | clasă).
Multinomial Naive Bayes
Modelează fiecare caracteristică drept un număr de apariții. Este cea mai potrivită pentru date textuale în care caracteristicile sunt frecvențe de cuvinte sau valori TF-IDF.
P(cuvânt_i | clasă) = (numărul de apariții ale cuvântului_i în clasă + alpha) / (numărul total de cuvinte din clasă + alpha * dimensiunea_vocabularului)
alpha este netezirea Laplace (explicată mai jos). Această variantă este instrumentul principal pentru clasificarea textului.
Gaussian Naive Bayes
Modelează fiecare caracteristică drept o distribuție normală. Este cea mai potrivită pentru caracteristici continue.
P(x_i | clasă) = (1 / sqrt(2 * pi * var)) * exp(-(x_i - medie)^2 / (2 * var))
Fiecare clasă primește propria medie și varianță pentru fiecare caracteristică. Metoda funcționează bine atunci când, în interiorul fiecărei clase, caracteristicile urmează într-adevăr o curbă în formă de clopot.
Bernoulli Naive Bayes
Modelează fiecare caracteristică drept binară (prezentă sau absentă). Este cea mai potrivită pentru texte scurte sau vectori de caracteristici binare.
P(cuvânt_i | clasă) = (documente din clasă care conțin cuvântul_i + alpha) / (numărul total de documente din clasă + 2 * alpha)
Spre deosebire de Multinomial, Bernoulli penalizează explicit absența unui cuvânt. Dacă „free” apare de obicei în spam, dar lipsește din acest e-mail, Bernoulli o consideră o dovadă împotriva clasei spam.
Notă tehnică a traducerii: Multinomial NB este un model pentru numărări; vectorii TF-IDF fracționari funcționează adesea bine empiric, dar nu urmează literal distribuția multinomială. Gaussian NB presupune atât verosimilități marginale gaussiene, cât și independență condiționată între caracteristici. În plus, acestea nu sunt singurele variante existente: biblioteci precum scikit-learn oferă și ComplementNB și CategoricalNB.
Când se folosește fiecare variantă
| Variantă | Tip de caracteristică | Cea mai potrivită pentru | Exemplu |
|---|---|---|---|
| Multinomial | Numărări sau frecvențe | Clasificarea textului, sac de cuvinte | Spam în e-mail, clasificare tematică |
| Gaussian | Valori continue | Date tabelare cu caracteristici aproximativ normale | Clasificarea Iris, date de la senzori |
| Bernoulli | Binare (0/1) | Texte scurte, vectori de caracteristici binare | Spam în SMS, caracteristici de prezență/absență |
Netezirea Laplace
Ce se întâmplă când un cuvânt apare în datele de testare, dar nu a apărut niciodată în datele de antrenare pentru o anumită clasă?
Fără netezire: P(cuvânt | clasă) = 0/N = 0. Un singur zero înmulțit în întregul produs face ca P(clasă | caracteristici) = 0, indiferent de toate celelalte dovezi. Un singur cuvânt nevăzut distruge întreaga predicție, oricât de multe alte dovezi o susțin.
Netezirea Laplace adaugă un număr mic alpha (de obicei 1) fiecărui număr de apariții al unei caracteristici:
P(cuvânt_i | clasă) = (număr(cuvânt_i, clasă) + alpha) / (total_cuvinte_în_clasă + alpha * dimensiunea_vocabularului)
Cu alpha=1, fiecare cuvânt primește cel puțin o probabilitate foarte mică. Apariția cuvântului „discombobulate” într-un e-mail de testare nu mai anulează probabilitatea de spam. Netezirea are o interpretare bayesiană: este echivalentă cu plasarea unei distribuții a priori Dirichlet uniforme peste distribuțiile cuvintelor.
Un alpha mai mare înseamnă o netezire mai puternică (distribuții mai uniforme). Un alpha mai mic înseamnă că modelul are mai multă încredere în date. Alpha este un hiperparametru pe care îl reglați.
Efectul lui alpha:
| Alpha | Efect | Când se folosește |
|---|---|---|
| 0,001 | Aproape fără netezire, încredere în date | Set de antrenare foarte mare, nu se așteaptă caracteristici nevăzute |
| 0,1 | Netezire ușoară | Set de antrenare mare |
| 1,0 | Netezire Laplace standard | Punct de pornire implicit |
| 10,0 | Netezire puternică, aplatizează distribuțiile | Set de antrenare foarte mic, se așteaptă multe caracteristici nevăzute |
Notă tehnică a traducerii:
alpha=1este netezire Laplace, iar valorile sub 1 sunt numite de obicei netezire Lidstone; tabelul oferă doar euristici. Netezirea alocă masă caracteristicilor cunoscute vocabularului, dar neobservate într-o anumită clasă. Un cuvânt complet în afara vocabularului fix este, de regulă, ignorat de vectorizator și nu primește automat probabilitate prin această formulă.
Calculul în spațiul logaritmic
Înmulțirea a sute de probabilități (fiecare mai mică decât 1) provoacă underflow în virgulă mobilă. Produsul devine zero în reprezentarea în virgulă mobilă, chiar dacă valoarea reală este un număr pozitiv foarte mic.
Soluția: lucrați în spațiul logaritmic. În loc să înmulțiți probabilitățile, adunați logaritmii lor:
log P(clasă | x1, x2, ..., xn) = log P(clasă) + sum_i log P(xi | clasă)
Astfel, predicția devine un produs scalar:
log_scores = X @ log_feature_probs.T + log_class_priors
prediction = argmax(log_scores)
Înmulțire de matrice. De aceea predicția Naive Bayes este atât de rapidă — este aceeași operație ca într-un model liniar cu un singur strat.
Notă tehnică a traducerii: Egalitatea pentru posterior omite din nou constanta de normalizare
-log P(x). Expresia din dreapta este un scor proporțional în spațiul logaritmic și este suficientă pentru clasificare; pentru probabilități posterior normalizate trebuie aplicată o normalizare stabilă, de exemplu log-sum-exp.
Naive Bayes în raport cu regresia logistică
Ambele sunt clasificatoare liniare pentru text. Diferența constă în ceea ce modelează.
| Aspect | Naive Bayes | Regresie logistică |
|---|---|---|
| Tip | Generativ (modelează P(X|Y)) | Discriminativ (modelează P(Y|X)) |
| Antrenare | Numără frecvențe | Optimizează o funcție de pierdere |
| Date puține | Mai bun (presupunerea puternică ajută) | Mai slabă (date insuficiente pentru estimarea ponderilor) |
| Date multe | Mai slab (ipoteza greșită dăunează) | Mai bună (frontieră flexibilă) |
| Caracteristici | Presupune independența | Gestionează corelațiile |
| Viteză | O singură trecere, foarte rapid | Optimizare iterativă |
| Calibrare | Probabilități slabe | Probabilități mai bune |
Regulă practică: începeți cu Naive Bayes. Dacă aveți suficiente date și NB ajunge la un platou, treceți la regresia logistică.
Notă tehnică a traducerii: Tabelul rezumă o tendință, nu o ordine garantată. Rezultatul clasic Ng–Jordan compară rate de convergență și erori asimptotice în anumite familii de modele; el nu spune că NB câștigă mereu cu puține date sau că regresia logistică îl depășește mereu cu multe. Regularizarea, reprezentarea și specificarea modelului influențează atât clasificarea, cât și calibrarea.
Pipeline de clasificare
În practică, lucrăm în spațiul logaritmic pentru a evita underflow-ul în virgulă mobilă. În loc să înmulțim multe probabilități mici, le adunăm logaritmii:
log P(clasă | caracteristici) = log P(clasă) + sum_i log P(caracteristică_i | clasă)
naive-bayes
Construiți
Codul din code/naive_bayes.py implementează de la zero atât MultinomialNB, cât și GaussianNB.
MultinomialNB
Implementarea de la zero:
-
fit(X, y): Pentru fiecare clasă, numără frecvența fiecărei caracteristici. Adaugă netezire Laplace. Calculează log-probabilitățile. Stochează probabilitățile a priori ale claselor (logaritmul frecvențelor claselor).
-
predict_log_proba(X): Pentru fiecare eșantion, calculează log P(clasă) + suma log P(caracteristică_i | clasă) pentru toate clasele. Aceasta este o înmulțire de matrice: X @ log_probs.T + log_priors.
-
predict(X): Returnează clasa cu cea mai mare log-probabilitate.
class MultinomialNB:
def __init__(self, alpha=1.0):
self.alpha = alpha
def fit(self, X, y):
classes = np.unique(y)
n_classes = len(classes)
n_features = X.shape[1]
self.classes_ = classes
self.class_log_prior_ = np.zeros(n_classes)
self.feature_log_prob_ = np.zeros((n_classes, n_features))
for i, c in enumerate(classes):
X_c = X[y == c]
self.class_log_prior_[i] = np.log(X_c.shape[0] / X.shape[0])
counts = X_c.sum(axis=0) + self.alpha
self.feature_log_prob_[i] = np.log(counts / counts.sum())
return self
Ideea-cheie: după ajustare, predicția este doar o înmulțire de matrice plus o deplasare. Acesta este motivul pentru care Naive Bayes este atât de rapid.
Notă tehnică a traducerii: În fișierul complet, metoda numită
predict_log_probareturnează scorurile comune nenormalizateX @ feature_log_prob_.T + class_log_prior_; nu aplică normalizarea log-sum-exp cerută de nume.predictrămâne corect pentruargmax, iarpredict_probanormalizează separat scorurile prin exponențiere stabilizată.
GaussianNB
Pentru caracteristici continue, estimăm media și varianța fiecărei caracteristici în fiecare clasă:
class GaussianNB:
def __init__(self):
pass
def fit(self, X, y):
classes = np.unique(y)
self.classes_ = classes
self.means_ = np.zeros((len(classes), X.shape[1]))
self.vars_ = np.zeros((len(classes), X.shape[1]))
self.priors_ = np.zeros(len(classes))
for i, c in enumerate(classes):
X_c = X[y == c]
self.means_[i] = X_c.mean(axis=0)
self.vars_[i] = X_c.var(axis=0) + 1e-9
self.priors_[i] = X_c.shape[0] / X.shape[0]
return self
Predicția folosește densitatea gaussiană pentru fiecare caracteristică, înmulțită peste toate caracteristicile (adunată în spațiul logaritmic).
Notă tehnică a traducerii: Constanta absolută
1e-9evită împărțirea la zero în acest exemplu, dar efectul ei depinde de scara caracteristicii. Implementările robuste folosesc un mecanism de stabilizare raportat la scara varianțelor și verifică sensibilitatea numerică.
Demonstrație: clasificarea textului
Codul generează date sintetice de tip sac de cuvinte, simulând două clase (articole despre tehnologie și articole despre sport). Fiecare clasă are o distribuție diferită a frecvențelor cuvintelor. MultinomialNB le clasifică folosind numărul de apariții ale cuvintelor.
Datele sintetice funcționează astfel: creăm 200 de „cuvinte” (coloane de caracteristici). Cuvintele 0–39 au frecvență mare în articolele despre tehnologie și mică în cele despre sport. Cuvintele 80–119 au frecvență mare în articolele despre sport și mică în cele despre tehnologie. Cuvintele 40–79 au frecvență medie în ambele. Astfel se creează un scenariu realist în care unele cuvinte sunt indicatori puternici ai clasei, iar altele sunt zgomot.
Demonstrație: caracteristici continue
Codul generează date asemănătoare cu Iris (3 clase, 4 caracteristici, clustere gaussiene). GaussianNB clasifică folosind media și varianța fiecărei clase. Fiecare clasă are un centru diferit (vector mediu) și o dispersie diferită (varianță), imitând date reale în care măsurătorile diferă sistematic între categorii.
Codul mai demonstrează:
- Comparația netezirii: Antrenarea MultinomialNB cu diferite valori alpha pentru a arăta efectul intensității netezirii asupra acurateții.
- Experimentul cu dimensiunea setului de antrenare: Cum se îmbunătățește acuratețea NB pe măsură ce datele de antrenare cresc de la 20 la 1.600 de eșantioane. NB atinge o acuratețe rezonabilă chiar și cu foarte puține eșantioane — acesta este principalul său avantaj.
- Matricea de confuzie: Precizie, recall și scor F1 pentru fiecare clasă, pentru a arăta unde greșește NB.
Notă tehnică a traducerii: Generatorul text folosește numărări Poisson independente, iar generatorul continuu folosește covarianțe diagonale. Datele sunt astfel construite aproape exact după ipotezele celor două modele; rezultatele nu testează robustețea față de corelațiile și schimbările de distribuție din textul ori datele tabelare reale. Afirmația despre avantajul cu puține eșantioane trebuie verificată pe fiecare problemă.
Viteza predicției
Predicția Naive Bayes este o înmulțire de matrice. Pentru n eșantioane cu d caracteristici și k clase:
- MultinomialNB: o înmulțire de matrice (n x d) @ (d x k) = O(n * d * k)
- GaussianNB: n * k evaluări ale densității gaussiene, fiecare peste d caracteristici = O(n * d * k)
Ambele sunt liniare în fiecare dimensiune. Comparați aceasta cu KNN (care necesită calcularea distanței până la toate punctele de antrenare) sau SVM cu nucleu RBF (care necesită evaluarea nucleului față de toți vectorii suport). NB este cu ordine de mărime mai rapid la predicție.
Notă tehnică a traducerii: Pentru o matrice rară, costul MultinomialNB poate fi exprimat mai precis prin numărul de elemente nenule, nu prin
n*d. Avantajul de „ordine de mărime” față de alte modele depinde de numărul vectorilor suport, de indexarea KNN, de densitatea datelor și de implementare; nu este garantat față de toate clasificatoarele liniare.
Folosiți
Cu sklearn, ambele variante se scriu într-o singură linie:
from sklearn.naive_bayes import GaussianNB, MultinomialNB
gnb = GaussianNB()
gnb.fit(X_train, y_train)
print(f"GaussianNB accuracy: {gnb.score(X_test, y_test):.3f}")
mnb = MultinomialNB(alpha=1.0)
mnb.fit(X_train_counts, y_train)
print(f"MultinomialNB accuracy: {mnb.score(X_test_counts, y_test):.3f}")
Pentru clasificarea textului cu sklearn:
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
text_clf = Pipeline([
("vectorizer", CountVectorizer()),
("classifier", MultinomialNB(alpha=1.0)),
])
text_clf.fit(train_texts, train_labels)
accuracy = text_clf.score(test_texts, test_labels)
Codul din naive_bayes.py compară implementările de la zero cu sklearn pe aceleași date pentru a verifica corectitudinea.
Notă tehnică a traducerii: Fișierul original
code/naive_bayes.pyimportă numai NumPy și nu conține nicio instanță ori comparație cu clasele sklearn. El compară între ele implementările proprii MultinomialNB și GaussianNB; afirmația despre verificarea față de sklearn nu este implementată în revizia sursă indicată în metadate.
TF-IDF cu Naive Bayes
Numărările brute ale cuvintelor acordă aceeași pondere fiecărei apariții. Dar cuvintele frecvente precum „the” și „is” apar des în fiecare clasă — ele nu poartă informație. TF-IDF (Term Frequency - Inverse Document Frequency) reduce ponderile cuvintelor frecvente și le mărește pe ale celor rare și discriminative.
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.pipeline import Pipeline
text_clf = Pipeline([
("tfidf", TfidfVectorizer()),
("classifier", MultinomialNB(alpha=0.1)),
])
Valorile TF-IDF sunt nenegative, deci funcționează cu MultinomialNB. Combinația TF-IDF + MultinomialNB este unul dintre cele mai puternice repere pentru clasificarea textului. Ea depășește frecvent modele mai complexe pe seturi de date cu mai puțin de 10.000 de eșantioane de antrenare.
Notă tehnică a traducerii:
TfidfVectorizerstandard produce valori nenegative, iar scikit-learn menționează că TF-IDF funcționează bine în practică, deși modelul MultinomialNB este derivat pentru numărări. Pragul de 10.000 de eșantioane și superioritatea față de modele complexe nu sunt reguli generale; trebuie comparate pe validare cu aceeași reprezentare și metrică.
BernoulliNB pentru texte scurte
Pentru texte scurte (tweeturi, SMS-uri, mesaje de chat), BernoulliNB poate depăși MultinomialNB. Textele scurte au puține apariții ale cuvintelor, astfel încât informația despre frecvență pe care se bazează MultinomialNB este zgomotoasă. BernoulliNB ține cont doar de prezență sau absență, care este mai fiabilă pentru texte scurte.
from sklearn.naive_bayes import BernoulliNB
from sklearn.feature_extraction.text import CountVectorizer
text_clf = Pipeline([
("vectorizer", CountVectorizer(binary=True)),
("classifier", BernoulliNB(alpha=1.0)),
])
Opțiunea binary=True din CountVectorizer convertește toate numărările în 0/1. Fără ea, BernoulliNB funcționează în continuare, dar vede numărări pentru care nu a fost proiectat.
Notă tehnică a traducerii: În scikit-learn,
BernoulliNBare implicitbinarize=0.0, astfel încât poate binariza intern valori numerice nenule chiar dacăCountVectorizer(binary=True)nu este folosit. Setarea explicită rămâne clară și utilă, dar afirmația că estimatorul ar folosi neapărat numărările brute nu este corectă pentru configurația implicită.
Calibrarea probabilităților NB
Probabilitățile NB sunt slab calibrate. Când NB spune P(spam) = 0,95, probabilitatea reală ar putea fi 0,7. Dacă aveți nevoie de estimări fiabile ale probabilității (de exemplu, pentru stabilirea unui prag sau combinarea cu alte modele), folosiți CalibratedClassifierCV din sklearn:
from sklearn.calibration import CalibratedClassifierCV
calibrated_nb = CalibratedClassifierCV(MultinomialNB(), cv=5, method="sigmoid")
calibrated_nb.fit(X_train, y_train)
proba = calibrated_nb.predict_proba(X_test)
Aceasta ajustează o regresie logistică peste scorurile brute NB folosind validarea încrucișată. Probabilitățile rezultate sunt mult mai apropiate de frecvențele reale ale claselor.
Notă tehnică a traducerii: Calibrarea sigmoidă învață un calibrator de tip Platt pe predicții obținute fără contaminarea pliului de calibrare; nu este o garanție că probabilitățile se îmbunătățesc pe orice set de date. Calibrarea trebuie evaluată separat, de exemplu prin diagrame de fiabilitate și metrici proprii, iar pliurile trebuie să conțină clasele relevante.
Capcane frecvente
-
Valori negative ale caracteristicilor. MultinomialNB necesită caracteristici nenegative. Dacă aveți valori negative (precum TF-IDF cu anumite setări sau caracteristici standardizate), folosiți GaussianNB în schimb sau translatați caracteristicile astfel încât să devină pozitive.
-
Caracteristici cu varianță zero. GaussianNB împarte la varianță. Dacă o caracteristică are varianță zero pentru o clasă (toate valorile sunt identice), calculul probabilității se strică. Codul adaugă un termen mic de netezire (1e-9) tuturor varianțelor pentru a preveni acest lucru.
-
Dezechilibrul claselor. Dacă 99% dintre e-mailuri sunt non-spam, probabilitatea a priori P(non-spam) = 0,99 este atât de puternică, încât copleșește dovezile din verosimilitate. Puteți seta manual probabilitățile a priori ale claselor sau folosi parametrul class_prior din sklearn.
-
Scalarea caracteristicilor. MultinomialNB nu are nevoie de scalare (lucrează cu numărări). Nici GaussianNB nu are nevoie de scalare (estimează statistici pentru fiecare caracteristică). Acesta este un avantaj față de regresia logistică și SVM, care sunt sensibile la scara caracteristicilor.
Notă tehnică a traducerii: TF-IDF produs de vectorizatorul standard nu este negativ. Translatarea arbitrară a unor caracteristici negative pentru a satisface MultinomialNB schimbă raporturile și nu transformă automat datele într-un model multinomial valid; alegerea GaussianNB nu este nici ea justificată fără ipoteze gaussiene. Probabilitățile a priori manuale și orice transformare trebuie validate pentru populația-țintă.
Livrați
Această lecție produce:
outputs/skill-naive-bayes-chooser.md— o abilitate de decizie pentru alegerea variantei NB potrivitecode/naive_bayes.py— MultinomialNB și GaussianNB de la zero
Când eșuează Naive Bayes
NB eșuează atunci când ipoteza de independență produce ierarhizări incorecte (nu doar probabilități incorecte). Acest lucru se întâmplă când:
-
Interacțiuni puternice între caracteristici. Dacă o clasă depinde de combinația a două caracteristici, dar nu de fiecare dintre ele separat (tipare asemănătoare cu XOR), NB o va rata complet. Fiecare caracteristică luată separat nu oferă nicio dovadă, iar NB nu le poate combina neliniar.
-
Caracteristici puternic corelate cu dovezi opuse. Dacă caracteristica A indică „spam”, iar caracteristica B indică „non-spam”, dar A și B sunt perfect corelate (în realitate sunt întotdeauna de acord), NB va vedea dovezi contradictorii acolo unde nu există.
-
Seturi de antrenare foarte mari. Cu suficiente date, modelele discriminative precum regresia logistică învață frontiera reală de decizie și depășesc NB. Ipoteza de independență care ajuta cu puține date limitează acum modelul.
În practică, aceste moduri de eșec sunt rare în clasificarea textului. Caracteristicile textuale sunt numeroase și slabe individual, iar erorile ipotezei de independență tind să se anuleze. Pentru date tabelare cu puține caracteristici puternic corelate, luați mai întâi în considerare regresia logistică sau modelele bazate pe arbori.
Notă tehnică a traducerii: XOR este un contraexemplu clar, însă celelalte concluzii nu sunt universale. Corelația poate duce la supra-numărarea dovezilor în diferite moduri, iar mai multe date nu garantează că regresia logistică depășește NB dacă modelul discriminativ este specificat greșit. Nici modurile de eșec nu sunt în mod demonstrabil „rare” pentru orice corpus textual; comparația trebuie făcută pe date reprezentative.
Exerciții
-
Experiment de netezire. Antrenați MultinomialNB pe date textuale cu valorile alpha 0,01, 0,1, 1,0, 10,0 și 100,0. Reprezentați grafic acuratețea în raport cu alpha. Unde atinge performanța valoarea maximă? De ce dăunează un alpha foarte mare?
-
Testul independenței caracteristicilor. Luați un set de date textuale reale. Alegeți două cuvinte evident corelate („machine” și „learning”). Calculați P(cuvânt1 | clasă) * P(cuvânt2 | clasă) și comparați cu P(cuvânt1 ȘI cuvânt2 | clasă). Cât de greșită este ipoteza de independență? Afectează acuratețea clasificării?
-
Implementare Bernoulli. Extindeți codul cu o clasă BernoulliNB. Convertiți sacul de cuvinte în valori binare (prezent/absent) și comparați acuratețea cu MultinomialNB pe date textuale. Când câștigă Bernoulli?
-
NB în raport cu regresia logistică. Antrenați-le pe amândouă pe date textuale. Începeți cu 100 de eșantioane de antrenare și creșteți la 10.000. Reprezentați grafic acuratețea în raport cu dimensiunea setului de antrenare pentru ambele. În ce punct depășește regresia logistică Naive Bayes?
-
Filtru de spam. Construiți un clasificator complet de spam: tokenizați textul brut al e-mailurilor, construiți vocabularul, creați caracteristici sac de cuvinte, antrenați MultinomialNB, evaluați-l cu precizie și recall (nu doar cu acuratețe — de ce?).
Termeni-cheie
| Termen | Ce spun oamenii | Ce înseamnă de fapt |
|---|---|---|
| Naive Bayes | „Clasificator probabilistic simplu” | Un clasificator care aplică teorema lui Bayes cu ipoteza că toate caracteristicile sunt independente condiționat de clasă |
| Independență condiționată | „Caracteristicile nu se influențează reciproc” | P(A, B | C) = P(A | C) * P(B | C) — cunoașterea lui B nu oferă nicio informație nouă despre A odată ce C este cunoscut |
| Netezire Laplace | „Netezire prin adăugarea unuia” | Adăugarea unui număr mic fiecărei caracteristici pentru a împiedica probabilitățile zero să domine predicția |
| Probabilitate a priori | „Ce credeați înainte de a vedea datele” | P(clasă) — probabilitatea fiecărei clase înainte de observarea vreunei caracteristici |
| Verosimilitate | „Cât de bine se potrivesc datele” | P(caracteristici | clasă) — probabilitatea observării acestor caracteristici atunci când clasa este cunoscută |
| Probabilitate a posteriori | „Ce credeți după ce vedeți datele” | P(clasă | caracteristici) — probabilitatea actualizată a clasei după observarea caracteristicilor |
| Model generativ | „Modelează modul în care sunt generate datele” | Un model care învață P(X | Y) și P(Y), apoi folosește teorema lui Bayes pentru a obține P(Y | X) |
| Model discriminativ | „Modelează frontiera de decizie” | Un model care învață direct P(Y | X), fără a modela modul în care este generat X |
| Log-probabilitate | „Evită underflow-ul” | Lucrul cu log P în loc de P pentru a împiedica produsul multor numere mici să devină zero în virgulă mobilă |
Lecturi suplimentare
- Documentația scikit-learn pentru Naive Bayes — toate cele trei variante, cu detalii matematice
- McCallum și Nigam, A Comparison of Event Models for Naive Bayes Text Classification (1998) — comparația clasică dintre Multinomial și Bernoulli pentru text
- Rennie et al., Tackling the Poor Assumptions of Naive Bayes Text Classifiers (2003) — îmbunătățiri ale NB pentru text
- Ng și Jordan, On Discriminative vs. Generative Classifiers (2001) — demonstrează că NB converge mai repede decât LR cu mai puține date
Sursă: Naive Bayes — original
Navigare: înapoi: 02.13 — Pipeline-uri de învățare automată · Faza 2 — Bazele învățării automate · Catalog complet · în continuare: 02.15 — Fundamentele seriilor temporale.