專項練習 · 11 分鐘閱讀

Python 樸素貝葉斯練習:計數、先驗與平滑

樸素貝葉斯大部分工作就是細緻地計數。這些練習構造計數表、轉成平滑機率、在對數空間比較類別,並在未參與訓練的文字上檢查結果。

練習:為每個類別建立計數表

標籤不是特徵。先按標籤拆分訓練文件,再在每個組內統計詞元。所有文件必須使用相同的分詞規則。

docs = [("good movie", "pos"), ("great film", "pos"), ("bad movie", "neg"), ("boring film", "neg")]
counts = {}
for text, label in docs:
    counts.setdefault(label, {})
    for word in text.split():
        counts[label][word] = counts[label].get(word, 0) + 1
print(counts["pos"])
print(counts["neg"])

按標籤分組的證據

練習:計算類別先驗

先驗是某個類別在文件中的佔比。當類別極不平衡時,它尤其重要。列印兩個先驗,並檢查它們之和為一。

labels = ["pos", "pos", "neg", "neg"]
for label in ("pos", "neg"):
    print(label, labels.count(label) / len(labels))

每個類別有多常見?

練習:平滑一個沒見過的詞

不做平滑時,某類別從未出現的詞會讓整個乘積變成零。給每個計數加一,並在分母加上詞表大小。

counts = {"great": 0}
total = 4
vocab_size = 6
probability = (counts.get("great", 0) + 1) / (total + vocab_size)
print(round(probability, 2))

是很小的機率,不是零

練習:比較對數分數

類別分數等於對數先驗加上每個詞的對數似然。比較兩個候選分數,不需要連乘很小的數。分數更大者獲勝,同時要規定確定性的平局規則。

import math

pos = math.log(0.5) + math.log(0.2) + math.log(0.2)
neg = math.log(0.5) + math.log(0.1) + math.log(0.1)
print(round(pos, 2), round(neg, 2))
print("pos" if pos > neg else "neg")

先加對數,再比較

練習:預測留出文字

用訓練文件建立模型,再給新文件分類。兩個例子上的準確率只是快速檢查,不能證明生產品質。

import math

train = [("good movie", "pos"), ("great film", "pos"), ("bad movie", "neg"), ("boring film", "neg")]
tests = [("great movie", "pos"), ("boring movie", "neg")]
vocab = sorted({word for text, _ in train for word in text.split()})
counts = {}
priors = {}
for text, label in train:
    priors[label] = priors.get(label, 0) + 1
    counts.setdefault(label, {})
    for word in text.split():
        counts[label][word] = counts[label].get(word, 0) + 1

def predict(text):
    scores = {}
    for label in counts:
        total = sum(counts[label].values())
        score = math.log(priors[label] / len(train))
        for word in text.split():
            score += math.log((counts[label].get(word, 0) + 1) / (total + len(vocab)))
        scores[label] = score
    return max(scores, key=scores.get)

correct = sum(predict(text) == label for text, label in tests)
print(correct / len(tests))

一次快速檢查,不是基準測試

你的練習清單

常見問題

樸素貝葉斯需要神經網路嗎?

不需要。它是基於計數的機率分類器,也是許多文字任務的強基線。

詞不在詞表裡怎麼辦?

常見做法是忽略它,或映射到訓練時已經存在的未知詞元特徵。要在評估前定好。

為什麼對數分數都是負數?

機率最大為一,所以對數最大為零。比較相對大小即可,不必糾結符號。

練習計數與計分

12 道題,覆蓋計數、先驗、平滑、對數分數與留出預測。

打開練習

繼續閱讀: