Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa
Odtwórz problem zerowego prawdopodobieństwa dla nieznanych słów i zobacz, jak wygładzanie Laplace’a zapobiega przypisywaniu przez model prawdopodobieństwa równego zero.
Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa to bezpłatna lekcja Machine Learning Academy na CoddyKit. To lekcja 4 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Machine Learning Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Machine Learning Academy zawiera 4 lekcji w sumie.
Katastrofa zerowego prawdopodobieństwa
Naive Bayes oblicza prawdopodobieństwo a posteriori klasy, mnożąc prawdopodobieństwa warunkowe wszystkich cech: P(class|features) ∝ P(class) * product of P(feature_i | class). Jeśli dowolna pojedyncza cecha ma zerowe prawdopodobieństwo w danej klasie — ponieważ nigdy nie wystąpiła w danych treningowych dla tej klasy — cały iloczyn wynosi zero, niezależnie od pozostałych cech. Oznacza to, że jedno niewidziane słowo uniemożliwia klasyfikatorowi rozróżnienie klas dla tego dokumentu. Jest to problem zerowego prawdopodobieństwa, szczególnie dotkliwy w przypadku danych tekstowych, gdzie słownictwo podczas testowania niemal zawsze zawiera słowa nieobecne w danych treningowych.
import numpy as np
# Training: 'bitcoin' never appeared in spam class
# Test document: 'buy bitcoin now cheap'
words_in_test = ['buy', 'bitcoin', 'now', 'cheap']
# Training probabilities (hypothetical)
P_word_given_spam = {'buy': 0.3, 'bitcoin': 0.0, 'now': 0.2, 'cheap': 0.4}
# Multiply likelihoods
product = 1.0
for word in words_in_test:
prob = P_word_given_spam.get(word, 0.0)
product *= prob
print(f'After {word}: product = {product}')
print('Final P(features|spam) =', product) # ZERO -- catastrophic!Dlaczego zerowe prawdopodobieństwo psuje model
Gdy P(features|class) = 0 jednocześnie dla wielu klas (co dzieje się w obecności niewidzianych słów), klasyfikator nie może ich rozróżnić — wszystkie prawdopodobieństwa a posteriori wynoszą 0. Gdy zerowe prawdopodobieństwo występuje tylko dla niektórych klas, klasyfikator jest zmuszony wybierać spośród pozostałych, które mogą być niewłaściwe. Nie jest to tylko niedogodność numeryczna — to fundamentalna awaria modelu. W przestrzeni logarytmów zerowe prawdopodobieństwo staje się ujemną nieskończonością: log(0) = -infinity. Dodanie wartości skończonych nadal daje -infinity, więc pojedyncze zero całkowicie dominuje prawdopodobieństwo logarytmiczne i pomija wszystkie pozostałe przesłanki.
import numpy as np
# In log-space: log(0) = -inf destroys the sum
log_probs = [np.log(0.3), np.log(0.0), np.log(0.2), np.log(0.4)]
for word, lp in zip(['buy', 'bitcoin', 'now', 'cheap'], log_probs):
print(f'log P({word}|spam) = {lp}')
log_posterior_spam = sum(log_probs)
print(f'\nLog P(spam|doc) = {log_posterior_spam}') # -inf
print('Prediction is dominated by the single zero probability!')Wygładzanie Laplace’a: dodawanie pseudoliczności
Wygładzanie Laplace’a (nazywane również wygładzaniem addytywnym lub wygładzaniem add-one) rozwiązuje problem zerowego prawdopodobieństwa, dodając małą stałą alpha do zliczenia każdego słowa przed obliczeniem prawdopodobieństw. Wzór przyjmuje postać: P(word | class) = (count(word, class) + alpha) / (total_words_in_class + alpha * vocab_size). Przy alpha=1 każde słowo otrzymuje co najmniej jedno „wirtualne” wystąpienie w każdej klasie. Gwarantuje to, że żadne słowo nie będzie miało zerowego prawdopodobieństwa, a jednocześnie minimalnie wpływa na słowa, które rzeczywiście często występowały w danych treningowych.
import numpy as np
def laplace_prob(count_word_class, total_words_class, vocab_size, alpha=1.0):
return (count_word_class + alpha) / (total_words_class + alpha * vocab_size)
# Parameters
total_spam_words = 1000
vocab_size = 5000
alpha = 1.0
# Word seen 50 times in spam
P_buy_spam = laplace_prob(50, total_spam_words, vocab_size, alpha)
print(f'P(buy|spam) = {P_buy_spam:.6f}') # High probability
# Word NEVER seen in spam (count=0)
P_bitcoin_spam = laplace_prob(0, total_spam_words, vocab_size, alpha)
print(f'P(bitcoin|spam) = {P_bitcoin_spam:.6f}') # Small but non-zero
print('Zero-probability problem solved!')Wpływ parametru alpha na prawdopodobieństwa
Parametr alpha określa, jak silne jest wygładzanie. Alpha=1 (wygładzanie Laplace’a) dodaje jedno wirtualne zliczenie każdego słowa dla każdej klasy. Większe wartości alpha powodują silniejsze wygładzanie — prawdopodobieństwa słów zbliżają się do rozkładu jednostajnego (1/vocab_size). Bardzo małe wartości alpha (0.001) zapewniają minimalne wygładzanie, ale są stabilne numerycznie. Optymalna wartość alpha równoważy eliminowanie zer z unikaniem nadmiernego wygładzania rzeczywistych sygnałów. Walidacja krzyżowa jest właściwą metodą wyboru alpha — w większości zadań klasyfikacji tekstu wartość ta zwykle mieści się w przedziale od 0.01 do 1.0.
import numpy as np
total_words = 1000
vocab_size = 5000
count_buy = 50 # Seen 50 times
count_new = 0 # Never seen
print('Alpha comparison for two words:')
print(f'{"alpha":>8} | {"P(buy|class)":>15} | {"P(unseen|class)":>18}')
print('-' * 50)
for alpha in [0.001, 0.01, 0.1, 1.0, 10.0]:
p_buy = (count_buy + alpha) / (total_words + alpha * vocab_size)
p_new = (count_new + alpha) / (total_words + alpha * vocab_size)
print(f'{alpha:>8.3f} | {p_buy:>15.6f} | {p_new:>18.6f}')Wygładzanie Lidstone’a: uogólnienie
Wygładzanie Lidstone’a jest uogólnioną postacią wygładzania Laplace’a, w której alpha może przyjmować dowolną dodatnią wartość, a nie tylko 1.0. Gdy alpha=1, mamy wygładzanie Laplace’a (add-one). Gdy alpha < 1, bywa ono nazywane wygładzaniem Jeffreysa–Perksa. Nie istnieje uniwersalnie najlepsza wartość alpha — zależy ona od rozmiaru słownictwa, wielkości danych treningowych i charakterystyki danych testowych. W przypadku dużych zbiorów treningowych (milionów dokumentów) dobrze sprawdzają się bardzo małe wartości alpha (0.001), ponieważ większość słów występuje w danych. W przypadku małych zbiorów treningowych większe wartości alpha zapobiegają nadmiernemu dopasowaniu do zaobserwowanych zliczeń słów.
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.pipeline import Pipeline
from sklearn.model_selection import GridSearchCV
from sklearn.datasets import fetch_20newsgroups
train = fetch_20newsgroups(subset='train',
categories=['sci.space', 'rec.sport.hockey'],
remove=('headers', 'footers', 'quotes'))
pipe = Pipeline([
('vec', CountVectorizer(stop_words='english')),
('nb', MultinomialNB())
])
# GridSearch over alpha (Lidstone smoothing parameter)
grid = GridSearchCV(pipe, {'nb__alpha': [0.001, 0.01, 0.1, 0.5, 1.0, 5.0]},
cv=5)
grid.fit(train.data, train.target)
print('Best alpha:', grid.best_params_['nb__alpha'])
print('Best CV accuracy:', grid.best_score_.round(4))Prezentacja rozwiązania: przed i po wygładzaniu
Oto konkretne porównanie pokazujące, jak wygładzanie zapobiega katastrofie zerowego prawdopodobieństwa. Bez wygładzania dokument zawierający jedno niewidziane słowo otrzymuje prawdopodobieństwo a posteriori równe 0 dla klasy, której to dotyczy. Po zastosowaniu wygładzania niewidziane słowo otrzymuje małe, ale dodatnie prawdopodobieństwo, dzięki czemu zachowany zostaje wpływ wszystkich pozostałych cech. Przewidywana klasa nie zmienia się, gdy niewidziane słowo nie ma mocy różnicującej, ale prawdopodobieństwo jest teraz sensowną wartością, a nie 0 lub -infinity.
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
import numpy as np
train_texts = ['buy cheap now offer deal', 'hello friend meeting lunch',
'discount click buy fast', 'project status update report']
train_labels = [1, 0, 1, 0]
vec = CountVectorizer()
X_train = vec.fit_transform(train_texts)
test_text = ['buy bitcoin now'] # 'bitcoin' unseen in training
X_test = vec.transform(test_text)
for alpha in [0.0, 1e-10, 1.0]:
nb = MultinomialNB(alpha=alpha if alpha > 0 else 1e-300)
nb.fit(X_train, train_labels)
prob = nb.predict_proba(X_test)
print(f'alpha={alpha}: P(ham)={prob[0][0]:.4f}, P(spam)={prob[0][1]:.4f}')Wygładzanie w praktyce: obsługa słownictwa
Wygładzanie pomaga również w przypadku słów spoza słownika (OOV) podczas wnioskowania. Słowa nieobecne w słowniku treningowym są domyślnie ignorowane przez CountVectorizer (nie otrzymują kolumny w macierzy cech). Słowa, które znajdowały się w słowniku, ale miały zerowe zliczenie w jednej z klas, są natomiast obsługiwane przez wygładzanie. Oba mechanizmy współdziałają: handle_unknown='ignore' w CountVectorizer (dla całkowicie niewidzianych słów) oraz alpha w MultinomialNB (dla słów o zerowym zliczeniu w obrębie słownika). Odporna potokowa architektura tekstowa korzysta z obu mechanizmów, aby radzić sobie z nieuniknionymi zmianami słownictwa między danymi treningowymi a danymi używanymi po wdrożeniu.
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
import numpy as np
train_texts = ['cat dog bird', 'fish tank water', 'dog cat pet']
train_labels = [0, 1, 0]
vec = CountVectorizer()
X_train = vec.fit_transform(train_texts)
print('Training vocabulary:', list(vec.vocabulary_.keys()))
# Test with fully unseen word 'elephant'
test = ['cat dog elephant'] # 'elephant' not in vocabulary
X_test = vec.transform(test)
print('OOV word silently ignored, only cat+dog encoded')
nb = MultinomialNB(alpha=1.0)
nb.fit(X_train, train_labels)
print('Prediction:', nb.predict(X_test))Wygładzanie dla innych wariantów naiwnego Bayesa
BernoulliNB stosuje wygładzanie Laplace’a w podobny sposób: zamiast prawdopodobieństw zliczeń słów wygładza binarne prawdopodobieństwa obecności P(feature=1|class) i P(feature=0|class). GaussianNB korzysta z innego podejścia — dodaje mały ułamek wariancji, aby uniknąć zerowej wariancji dla stałych cech: var_smoothing dodaje do wszystkich wariancji ten ułamek największej wariancji w zbiorze danych. Każdy wariant ma mechanizm wygładzania odpowiedni dla przyjętego założenia o rozkładzie, ale wszystkie mają ten sam podstawowy cel: zapobiegać zerowym prawdopodobieństwom, które spowodowałyby awarię modelu.
from sklearn.naive_bayes import BernoulliNB, GaussianNB
import numpy as np
# BernoulliNB with alpha smoothing (same as MultinomialNB)
bnb = BernoulliNB(alpha=1.0)
# GaussianNB with var_smoothing to prevent zero variance
gnb = GaussianNB(var_smoothing=1e-9) # Default: 1e-9 of max variance
print('BernoulliNB smooths P(feature=1|class) with alpha')
print('GaussianNB smooths variance with var_smoothing')
print('Both prevent zero probabilities in their respective distributions')
# var_smoothing default prevents failure on constant features
import numpy as np
X = np.array([[1,1],[2,2],[3,3],[1,2]])
y = np.array([0,0,1,1])
gnb.fit(X, y)
print('GaussianNB trained successfully even with near-constant features')Związek z regularyzacją w innych modelach
Wygładzanie Laplace’a w naiwnym Bayesie jest koncepcyjnie podobne do regularyzacji L2 w regresji logistycznej lub zaniku wag w sieciach neuronowych. Wszystkie trzy mechanizmy zapobiegają ekstremalnym wartościom parametrów, przesuwając oszacowania w kierunku neutralnej wartości bazowej (rozkładu jednostajnego w przypadku Laplace’a, zerowych wag w przypadku L2). Kluczowa różnica polega na tym, że wygładzanie Laplace’a dotyczy oszacowań prawdopodobieństwa i ma jasną interpretację bayesowską — jest równoważne dodaniu alpha wyobrażonych obserwacji każdego słowa do każdej klasy. Większa wartość alpha odpowiada silniejszemu przekonaniu a priori, że wszystkie słowa są jednakowo prawdopodobne, co przyciąga oszacowania w kierunku rozkładu jednostajnego.
# Bayesian interpretation of Laplace smoothing:
# Laplace smoothing = Dirichlet prior on word probabilities
# alpha=1 = uniform Dirichlet prior (all words equally likely before data)
# alpha -> 0 = no prior (maximum likelihood, prone to zero probs)
# alpha -> inf = strong prior (all words equally likely, ignores data)
import numpy as np
alphas = [0.001, 0.1, 1.0, 10.0, 100.0]
for alpha in alphas:
# Word counts: 'buy' seen 10x, 'rocket' seen 0x in spam (1000 words, 5000 vocab)
p_buy = (10 + alpha) / (1000 + alpha * 5000)
p_rocket = (0 + alpha) / (1000 + alpha * 5000)
ratio = p_buy / p_rocket
print(f'alpha={alpha:6.3f}: P(buy)/P(unseen) = {ratio:.1f}x')Testowanie wygładzania w scenariuszu rzeczywistym
Aby jednoznacznie wykazać wartość wygładzania, należy porównać modele z wygładzaniem i bez niego na zbiorze danych, w którym niektóre słowa testowe rzeczywiście nie występują w danych treningowych. Można sztucznie utworzyć taki przypadek, trenując model na małym korpusie i testując go na większym. Bez wygładzania dokładność gwałtownie spada, ponieważ słowa spoza słownika dla określonych klas powodują zerowe prawdopodobieństwa a posteriori. Dzięki wygładzaniu model sprawnie obsługuje nowe słowa i koncentruje się na tych, które rozpoznaje. Ta odporność sprawia, że Naive Bayes z wygładzaniem pozostaje mocnym modelem bazowym nawet dziesięciolecia po jego wprowadzeniu.
from sklearn.naive_bayes import MultinomialNB
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.datasets import fetch_20newsgroups
from sklearn.metrics import accuracy_score
train = fetch_20newsgroups(subset='train',
categories=['sci.space', 'rec.sport.hockey'],
remove=('headers','footers','quotes'))
test = fetch_20newsgroups(subset='test',
categories=['sci.space', 'rec.sport.hockey'],
remove=('headers','footers','quotes'))
vec = CountVectorizer(stop_words='english')
X_tr = vec.fit_transform(train.data)
X_te = vec.transform(test.data)
for alpha in [1e-10, 0.01, 0.1, 1.0]:
nb = MultinomialNB(alpha=alpha)
nb.fit(X_tr, train.target)
acc = accuracy_score(test.target, nb.predict(X_te))
print(f'alpha={alpha}: test accuracy = {acc:.4f}')Równoważność wygładzania z rozkładem a priori Dirichleta
Z perspektywy bayesowskiej wygładzanie Laplace’a jest równoważne przyjęciu symetrycznego rozkładu a priori Dirichleta dla rozkładu prawdopodobieństw słów w każdej klasie. Rozkład Dirichleta jest sprzężonym rozkładem a priori dla rozkładu wielomianowego, co oznacza, że rozkład a posteriori (przy zaobserwowanych zliczeniach słów) również ma postać rozkładu Dirichleta, a oszacowanie MAP (maximum a posteriori) jest dokładnie wzorem na prawdopodobieństwo wygładzone metodą Laplace’a. Alpha jest parametrem koncentracji rozkładu a priori Dirichleta: alpha=1 oznacza rozkład jednostajny (wszystkie słowa są jednakowo prawdopodobne a priori), alpha<1 oznacza rozkład rzadki (większość słów ma a priori prawdopodobieństwo bliskie zeru), a alpha>1 oznacza rozkład gęsty (przesuwa wszystkie słowa w kierunku jednakowego prawdopodobieństwa). To ujęcie bayesowskie wyjaśnia, dlaczego małe wartości alpha są odpowiednie dla dużych korpusów, a duże wartości alpha dla małych korpusów.
import numpy as np
# Dirichlet-Multinomial MAP estimate = Laplace smoothing
# P(word_i | class) = (count_i + alpha) / (N + V * alpha)
# where V = vocabulary size, N = total words seen in class
# For large corpus:
N_large = 1_000_000 # 1 million words in class
V = 50_000 # 50k vocabulary
count_unseen = 0
for alpha in [0.001, 0.01, 0.1, 1.0]:
p_unseen = (count_unseen + alpha) / (N_large + V * alpha)
print(f'alpha={alpha:.3f}: P(unseen|class) = {p_unseen:.2e}')
# Very small alpha keeps unseen words near-zero (good for large corpus)
# Large alpha smoothes too aggressively, inflates unseen word probsSzybkie sprawdzenie
Sprawdź swoją znajomość zagadnień uczenia maszynowego w Pythonie omówionych w tej lekcji.
Podsumowanie lekcji
W tej lekcji nauczyli się Państwo, że problem zerowego prawdopodobieństwa pojawia się, gdy nieznane słowa powodują spadek całego prawdopodobieństwa a posteriori do zera, wygładzanie Laplace’a dodaje pseudoliczniki alfa, aby zagwarantować każdemu słowu dodatnie prawdopodobieństwo, a optymalna wartość alfa jest hiperparametrem dostrajanym za pomocą walidacji krzyżowej, który zapewnia równowagę między eliminowaniem zer a nadmiernym wygładzaniem rzeczywistych sygnałów. Następnie omówimy metryki klasyfikacji, w tym dokładność, precyzję, czułość i wynik F1.
Ucz się Python dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 30
- Lekcje
- 120
Często zadawane pytania
Czy lekcja „Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa” jest bezpłatna?
Tak — pełny tekst „Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Machine Learning Academy, przejdź na CoddyKit PRO. Kurs Machine Learning Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa”?
Odtwórz problem zerowego prawdopodobieństwa dla nieznanych słów i zobacz, jak wygładzanie Laplace’a zapobiega przypisywaniu przez model prawdopodobieństwa równego zero. Ćwiczysz Machine Learning Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Machine Learning Academy?
Nie wymagamy żadnego doświadczenia. Machine Learning Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 4 z 4.
Ile czasu zajmuje lekcja „Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Machine Learning Academy?
Tak. Każda lekcja Machine Learning Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Twierdzenie Bayesa prostym językiem
- Bag of Words: CountVectorizer i TfidfVectorizer
- Trenowanie klasyfikatora Multinomial Naive Bayes
- Wygładzanie Laplace’a i problem zerowego prawdopodobieństwa