從“樸素”到“半樸素”:貝葉斯分類器的進階之路
在機器學習分類任務中,樸素貝葉斯(Naive Bayes)因其簡單高效而廣受歡迎,但它的“樸素”之名也暗示了其局限性。
為了突破這一局限,半樸素貝葉斯(Semi-Naive Bayes) 應運而生。
本文將詳細介紹樸素貝葉斯和半樸素貝葉斯的原理、應用場景以及如何使用scikit-learn庫實現它們。
1. 樸素貝葉斯:簡單但“天真”
樸素貝葉斯是一種基于貝葉斯定理的簡單概率分類器,它的核心思想是利用特征之間的獨立性假設來簡化計算。
具體來說,樸素貝葉斯假設每個特征之間是相互獨立的,即給定一個類別標簽,所有特征的聯合概率可以分解為各個特征的條件概率的乘積。
用數學公式表示為:$ P(X|Y)=P(x_1|Y)\times P(x_2|Y)\times\cdots\times P(x_n|Y) $
其中,$ X \(是特征向量,\) Y \(是類別標簽,\) x_1,x_2,\ldots,x_n $是各個特征。
樸素貝葉斯的優勢在于計算高效,適合高維數據(如新聞分類)。
2. 半樸素貝葉斯:放松獨立性假設
盡管樸素貝葉斯在許多場景下表現出色,但它的一個關鍵假設:特征獨立性,在實際應用中往往難以滿足。
在現實世界中,特征之間通常存在一定的相關性。
例如,在文本分類中,某些詞匯的出現可能與其他詞匯的出現密切相關。
這種情況下,樸素貝葉斯的獨立性假設會導致分類器的性能下降。
為了解決這一問題,半樸素貝葉斯應運而生。
半樸素貝葉斯在一定程度上放寬了特征獨立性的假設,允許特征之間存在一定的相關性,從而提高分類器的性能。
半樸素貝葉斯的核心改進在于允許部分特征之間存在依賴關系,通過捕捉關鍵特征間的依賴,提升分類精度,同時保持計算復雜度可控。
3. 實戰對比
下面構造一個簡單的示例,用來對比樸素和半樸素貝葉斯的在屬性存在依賴關系時的準確率。
首先,生成測試數據:
- 類別
Y有兩種值,0和1 - 類別
Y決定X1的分布(Y=0時均值為0,Y=1時均值為1) X2依賴于X1(X2 = X1 + 噪聲),模擬屬性間的依賴關系
import numpy as np
from sklearn.model_selection import train_test_split
# 生成模擬數據:Y影響X1和X2,且X2依賴X1
np.random.seed(42)
n_samples = 1000
Y = np.random.randint(0, 2, n_samples)
X1 = np.zeros(n_samples)
X2 = np.zeros(n_samples)
for i in range(n_samples):
if Y[i] == 0:
x1 = np.random.normal(0, 1)
x2 = x1 + np.random.normal(0, 0.5) # X2依賴X1
else:
x1 = np.random.normal(1, 1)
x2 = x1 + np.random.normal(0, 0.5) # X2依賴X1
X1[i] = x1
X2[i] = x2
X = np.vstack((X1, X2)).T
X_train, X_test, y_train, y_test = train_test_split(
X,
Y,
test_size=0.3,
random_state=42,
)
然后分別使用樸素和半樸素貝葉斯模型來訓練數據,看看各自的準確率。
注意,scikit-learn沒有直接提供半樸素貝葉斯的實現,下面的示例中通過手動計算特征之間的相關性來改進樸素貝葉斯模型。
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
from sklearn.linear_model import LinearRegression
# 樸素貝葉斯(假設屬性獨立)
nb = GaussianNB()
nb.fit(X_train, y_train)
y_pred_nb = nb.predict(X_test)
acc_nb = accuracy_score(y_test, y_pred_nb)
# 半樸素貝葉斯(手動實現,假設X2依賴X1)
# 訓練階段:估計每個類別的參數
def train_semi_naive_bayes(X, y):
params = {}
for cls in [0, 1]:
X_cls = X[y == cls]
X1_cls = X_cls[:, 0]
X2_cls = X_cls[:, 1]
# 估計P(X1|Y)的參數(高斯分布)
mu_X1 = np.mean(X1_cls)
sigma_X1 = np.std(X1_cls)
# 估計P(X2|Y,X1)的參數(線性回歸)
lr = LinearRegression().fit(X1_cls.reshape(-1, 1), X2_cls)
a, b = lr.coef_[0], lr.intercept_
residuals = X2_cls - lr.predict(X1_cls.reshape(-1, 1))
sigma_X2_given_X1 = np.std(residuals)
params[cls] = {
"prior": np.sum(y == cls) / len(y),
"mu_X1": mu_X1,
"sigma_X1": sigma_X1,
"a": a,
"b": b,
"sigma_X2_given_X1": sigma_X2_given_X1,
}
return params
# 預測階段:計算對數概率
def predict_semi_naive_bayes(X, params):
y_pred = []
for x1, x2 in X:
log_prob = {0: 0, 1: 0}
for cls in [0, 1]:
p = params[cls]
# 計算P(Y)
log_prob[cls] += np.log(p["prior"])
# 計算P(X1|Y)
log_prob[cls] += -0.5 * np.log(2 * np.pi * p["sigma_X1"] ** 2) - (
x1 - p["mu_X1"]
) ** 2 / (2 * p["sigma_X1"] ** 2)
# 計算P(X2|Y,X1)
mu_x2 = p["a"] * x1 + p["b"]
log_prob[cls] += -0.5 * np.log(2 * np.pi * p["sigma_X2_given_X1"] ** 2) - (
x2 - mu_x2
) ** 2 / (2 * p["sigma_X2_given_X1"] ** 2)
y_pred.append(0 if log_prob[0] > log_prob[1] else 1)
return np.array(y_pred)
params = train_semi_naive_bayes(X_train, y_train)
y_pred_semi = predict_semi_naive_bayes(X_test, params)
acc_semi = accuracy_score(y_test, y_pred_semi)
# 輸出結果
print(f"樸素貝葉斯準確率: {acc_nb:.4f}")
print(f"半樸素貝葉斯準確率: {acc_semi:.4f}")
## 輸出結果:
'''
樸素貝葉斯準確率: 0.6333
半樸素貝葉斯準確率: 0.7000
'''
樸素貝葉斯因假設屬性獨立,在X1和X2存在依賴時性能略有下降。
而半樸素貝葉斯通過顯式建模X2對X1的依賴,更準確地估計聯合概率,從而獲得更高的準確率。
此示例簡單展示了半樸素貝葉斯在屬性存在依賴關系時的優勢。
4. 總結
樸素貝葉斯和半樸素貝葉斯都是基于貝葉斯定理的分類算法。
其中,樸素貝葉斯假設特征之間相互獨立,適用于特征獨立性較強的場景,比如:
- 特征獨立性較強:當特征之間確實相互獨立時,樸素貝葉斯能夠發揮其優勢。例如,在垃圾郵件分類中,郵件中的詞匯通常可以被視為獨立的特征。
- 數據量較少:由于樸素貝葉斯的計算復雜度較低,它在數據量較少的情況下也能快速訓練模型。
- 對分類精度要求不高:在一些對分類精度要求不高的場景中,樸素貝葉斯可以作為一種快速且有效的解決方案。
而半樸素貝葉斯在一定程度上放寬了這一假設,適用于特征存在相關性的場景,比如:
- 特征存在相關性:當特征之間存在一定的相關性時,半樸素貝葉斯可以更好地捕捉這些關系,從而提高分類性能。例如,在醫學診斷中,某些癥狀之間可能存在關聯。
- 對分類精度要求較高:在需要高精度分類的場景中,半樸素貝葉斯可以通過考慮特征之間的相關性來提升性能。
- 數據量較大:當有足夠的數據來估計特征之間的相關性時,半樸素貝葉斯能夠更好地發揮其優勢。

浙公網安備 33010602011771號