關注微信公共號:小程在線
關注CSDN博客:程志偉的博客
Sklearn基於這些分佈以及這些分佈上的概率估計的改進,爲我們提供了四個樸素貝葉斯的分類器
類 | 含義 |
naive_bayes.BernoulliNB | 伯努利分佈下的樸素貝葉斯 |
naive_bayes.GaussianNB | 高斯分佈下的樸素貝葉斯 |
naive_bayes.MultinomialNB | 多項式分佈下的樸素貝葉斯 |
naive_bayes.ComplementNB | 補集樸素貝葉斯 |
linear_model.BayesianRidge | 貝葉斯嶺迴歸,在參數估計過程中使用貝葉斯迴歸技術來包括正則化參數 |
雖然樸素貝葉斯使用了過於簡化的假設,這個分類器在許多實際情況中都運行良好,著名的是文檔分類和垃圾郵件過濾。而且由於貝葉斯是從概率角度進行估計,它所需要的樣本量比較少,極端情況下甚至我們可以使用1%的數據作爲訓練集,依然可以得到很好的擬合效果。
1 不同分佈下的貝葉斯
1.1 高斯樸素貝葉斯GaussianNB
1.1.1 認識高斯樸素貝葉斯
class sklearn.naive_bayes.GaussianNB (priors=None, var_smoothing=1e-09)
高斯樸素貝葉斯,通過假設 是服從高斯分佈(也就是正態分佈),來估計每個特徵下每個類別上的條件概率。對於每個特徵下的取值,高斯樸素貝葉斯有如下公式:
對於任意一個Y的取值,貝葉斯都以求解最大化的 爲目標,這樣我們才能夠比較在不同標籤下我們的樣本究竟更靠近哪一個取值。以最大化 爲目標,高斯樸素貝葉斯會爲我們求解公式中的參數 和 。求解出參數後,帶入一個 的值,就能夠得到一個 的概率取值。
導入需要的庫和數據
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.datasets import load_digits
from sklearn.model_selection import train_test_split
digits = load_digits()
X, y = digits.data, digits.target
Xtrain,Xtest,Ytrain,Ytest = train_test_split(X,y,test_size=0.3,random_state=420)
查看訓練集數據的維度
Xtrain.shape
Out[4]: (1257, 64)
查看有幾個不同的標籤
np.unique(Ytrain)
Out[5]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
建模,探索建模結果
gnb = GaussianNB().fit(Xtrain,Ytrain)
#查看分數
acc_score = gnb.score(Xtest,Ytest)
acc_score
Out[7]: 0.8592592592592593
#查看預測的概率結果
prob = gnb.predict_proba(Xtest)
prob.shape
Out[8]: (540, 10)
prob[1,:]
Out[9]:
array([0.00000000e+00, 1.00000000e+00, 9.26742456e-13, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00,
0.00000000e+00, 0.00000000e+00])
#每一行的和都是一
prob[1,:].sum()
Out[10]: 1.000000000000003
prob.sum(axis=1).shape
Out[11]: (540,)
#查看預測結果
Y_pred = gnb.predict(Xtest)
使用混淆矩陣來查看貝葉斯的分類結果
from sklearn.metrics import confusion_matrix as CM
CM(Ytest,Y_pred)
Out[14]:
array([[47, 0, 0, 0, 0, 0, 0, 1, 0, 0],
[ 0, 46, 2, 0, 0, 0, 0, 3, 6, 2],
[ 0, 2, 35, 0, 0, 0, 1, 0, 16, 0],
[ 0, 0, 1, 40, 0, 1, 0, 3, 4, 0],
[ 0, 0, 1, 0, 39, 0, 1, 4, 0, 0],
[ 0, 0, 0, 2, 0, 58, 1, 1, 1, 0],
[ 0, 0, 1, 0, 0, 1, 49, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0, 0, 54, 0, 0],
[ 0, 3, 0, 1, 0, 0, 0, 2, 55, 0],
[ 1, 1, 0, 1, 2, 0, 0, 3, 7, 41]], dtype=int64)
ROC曲線是不能用於多分類的。多分類狀況下最佳的模型評估指標是混淆矩陣和整體的準確度
1.1.2 探索貝葉斯:高斯樸素貝葉斯擅長的數據集
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import ListedColormap
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.datasets import make_moons, make_circles, make_classification
from sklearn.naive_bayes import GaussianNB, MultinomialNB, BernoulliNB, ComplementNB
h = .02
names = ["Multinomial","Gaussian","Bernoulli","Complement"]
classifiers = [MultinomialNB(),GaussianNB(),BernoulliNB(),ComplementNB()]
X, y = make_classification(n_features=2, n_redundant=0, n_informative=2,
random_state=1, n_clusters_per_class=1)
rng = np.random.RandomState(2)
X += 2 * rng.uniform(size=X.shape)
linearly_separable = (X, y)
datasets = [make_moons(noise=0.3, random_state=0),
make_circles(noise=0.2, factor=0.5, random_state=1),
linearly_separable
]
figure = plt.figure(figsize=(6, 9))
i = 1
for ds_index, ds in enumerate(datasets):
X, y = ds
X = StandardScaler().fit_transform(X)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.4,
random_state=42)
x1_min, x1_max = X[:, 0].min() - .5, X[:, 0].max() + .5
x2_min, x2_max = X[:, 1].min() - .5, X[:, 1].max() + .5
array1,array2 = np.meshgrid(np.arange(x1_min, x1_max, 0.2),
np.arange(x2_min, x2_max, 0.2))
cm = plt.cm.RdBu
cm_bright = ListedColormap(['#FF0000', '#0000FF'])
ax = plt.subplot(len(datasets), 2, i)
if ds_index == 0:
ax.set_title("Input data")
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train,
cmap=cm_bright,edgecolors='k')
ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test,
cmap=cm_bright, alpha=0.6,edgecolors='k')
ax.set_xlim(array1.min(), array1.max())
ax.set_ylim(array2.min(), array2.max())
ax.set_xticks(())
ax.set_yticks(())
i += 1
ax = plt.subplot(len(datasets),2,i)
clf = GaussianNB().fit(X_train, y_train)
score = clf.score(X_test, y_test)
Z = clf.predict_proba(np.c_[array1.ravel(),array2.ravel()])[:, 1]
Z = Z.reshape(array1.shape)
ax.contourf(array1, array2, Z, cmap=cm, alpha=.8)
ax.scatter(X_train[:, 0], X_train[:, 1], c=y_train, cmap=cm_bright,
edgecolors='k')
ax.scatter(X_test[:, 0], X_test[:, 1], c=y_test, cmap=cm_bright,
edgecolors='k', alpha=0.6)
ax.set_xlim(array1.min(), array1.max())
ax.set_ylim(array2.min(), array2.max())
ax.set_xticks(())
ax.set_yticks(())
if ds_index == 0:
ax.set_title("Gaussian Bayes")
ax.text(array1.max() - .3, array2.min() + .3, ('{:.1f}%'.format(score*100)),
size=15, horizontalalignment='right')
i += 1
plt.tight_layout()
plt.show()

從圖上來看,高斯貝葉斯屬於比較特殊的一類分類器,其分類效果在二分數據和月亮型數據上表現優秀,但是環形數
據不太擅長。我們之前學過的模型中,許多線性模型比如邏輯迴歸,線性SVM等等,在線性數據集上會繪製直線決策
邊界,因此難以對月亮型和環形數據進行區分,但高斯樸素貝葉斯的決策邊界是曲線,可以是環形也可以是弧線,所
以儘管貝葉斯本身更加擅長線性可分的二分數據,但樸素貝葉斯在環形數據和月亮型數據上也可以有遠遠勝過其他線
性模型的表現
1.1.3 探索貝葉斯:高斯樸素貝葉斯的擬合效果與運算速度
1. 首先導入需要的模塊和庫
import numpy as np
import matplotlib.pyplot as plt
from sklearn.naive_bayes import GaussianNB
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier as RFC
from sklearn.tree import DecisionTreeClassifier as DTC
from sklearn.linear_model import LogisticRegression as LR
from sklearn.datasets import load_digits
from sklearn.model_selection import learning_curve
from sklearn.model_selection import ShuffleSplit
from time import time
import datetime
2. 定義繪製學習曲線的函數
#找出每個圖像的橫縱座標,learning_curve
#繪製子圖所在的子圖
def plot_learning_curve(estimator,title, X, y,
ax, #選擇子圖
ylim=None, #設置縱座標的取值範圍
cv=None, #交叉驗證
n_jobs=None #設定索要使用的線程
):
train_sizes, train_scores, test_scores = learning_curve(estimator, X, y
,cv=cv,n_jobs=n_jobs)
ax.set_title(title)
if ylim is not None:
ax.set_ylim(*ylim)
ax.set_xlabel("Training examples")
ax.set_ylabel("Score")
ax.grid() #顯示網格作爲背景,不是必須
ax.plot(train_sizes, np.mean(train_scores, axis=1), 'o-', color="r",label="Training score")
ax.plot(train_sizes, np.mean(test_scores, axis=1), 'o-', color="g",label="Test score")
ax.legend(loc="best")
return ax
3. 導入數據,定義循環
digits = load_digits()
X, y = digits.data, digits.target
title = ["Naive Bayes","DecisionTree","SVM, RBF kernel","RandomForest","Logistic"]
model = [GaussianNB(),DTC(),SVC(gamma=0.001),RFC(n_estimators=50),LR(C=.1,solver="lbfgs")]
cv = ShuffleSplit(n_splits=50, test_size=0.2, random_state=0)
4. 進入循環,繪製學習曲線
fig, axes = plt.subplots(1,5,figsize=(30,6))
for ind,title_,estimator in zip(range(len(title)),title,model):
times = time()
plot_learning_curve(estimator, title_, X, y,
ax=axes[ind], ylim = [0.7, 1.05],n_jobs=4, cv=cv)
print("{}:{}".format(title_,datetime.datetime.fromtimestamp(time()-times).strftime("%M:%S:%f")))
plt.show()
Naive Bayes:00:06:160353
DecisionTree:00:02:359413
SVM, RBF kernel:00:12:704179
RandomForest:00:15:797081
Logistic:00:40:925605

我們首先返回的結果是各個算法的運行時間。可以看到,決策樹和貝葉斯不相伯仲。決策樹之所以能夠運行非常快速是因爲
sklearn中的分類樹在選擇特徵時有所“偷懶”,沒有計算全部特徵的信息熵而是隨機選擇了一部分特徵來進行計算,因
此速度快可以理解,但我們知道決策樹的運算效率隨着樣本量逐漸增大會越來越慢,但樸素貝葉斯卻可以在很少的樣
本上獲得不錯的結果,因此我們可以預料,隨着樣本量的逐漸增大貝葉斯會逐漸變得比決策樹更快。樸素貝葉斯計算
速度遠遠勝過SVM,隨機森林這樣複雜的模型,邏輯迴歸的運行受到最大迭代次數的強烈影響和輸入數據的影響(邏
輯迴歸一般在線性數據上運行都比較快,但在這裏應該是受到了稀疏矩陣的影響)。因此在運算時間上,樸素貝葉斯
還是十分有優勢的。
我們來看一下每個算法在訓練集上的擬合。手寫數字數據集是一個較爲簡單的數據集,決策樹,森林,SVC
和邏輯迴歸都成功擬合了100%的準確率,但貝葉斯的最高訓練準確率都沒有超過95%,這也應證了我們最開始說
的,樸素貝葉斯的分類效果其實不如其他分類器,貝葉斯天生學習能力比較弱。並且我們注意到,隨着訓練樣本量的
逐漸增大,其他模型的訓練擬合都保持在100%的水平,但貝葉斯的訓練準確率卻逐漸下降,這證明樣本量越大,貝
葉斯需要學習的東西越多,對訓練集的擬合程度也越來越差。反而比較少量的樣本可以讓貝葉斯有較高的訓練準確
率。
過擬合問題。首先一眼看到,所有模型在樣本量很少的時候都是出於過擬合狀態的(訓練集上表現好,測試
集上表現糟糕),但隨着樣本的逐漸增多,過擬合問題都逐漸消失了,不過每個模型的處理手段不同。比較強大的分
類器們,比如SVM,隨機森林和邏輯迴歸,是依靠快速升高模型在測試集上的表現來減輕過擬合問題。相對的,決策
樹雖然也是通過提高模型在測試集上的表現來減輕過擬合,但隨着訓練樣本的增加,模型在測試集上的表現善生卻非
常緩慢。樸素貝葉斯獨樹一幟,是依賴訓練集上的準確率下降,測試集上的準確率上升來逐漸解決過擬合問題。
每個算法在測試集上的擬合結果,即泛化誤差的大小。隨着訓練樣本數量的上升,所有模型的測試表現。
都上升了,但貝葉斯和決策樹在測試集上的表現遠遠不如SVM,隨機森林和邏輯迴歸。SVM在訓練數據量增大到
1500個樣本左右的時候,測試集上的表現已經非常接近100%,而隨機森林和邏輯迴歸的表現也在95%以上,而決策
樹和樸素貝葉斯還徘徊在85%左右。但這兩個模型所面臨的情況十分不同:決策樹雖然測試結果不高,但是卻依然具
有潛力,因爲它的過擬合現象非常嚴重,我們可以通過減枝來讓決策樹的測試結果逼近訓練結果。然而貝葉斯的過擬
合現象在訓練樣本達到1500左右的時候已經幾乎不存在了,訓練集上的分數和測試集上的分數非常接近,只有在非
常少的時候測試集上的分數才能夠比訓練集上的結果更高,所以我們基本可以判斷,85%左右就是貝葉斯在這個數據
集上的極限了。可以預測到,如果我們進行調參,那決策樹最後應該可以達到90%左右的預測準確率,但貝葉斯卻幾
乎沒有潛力了。
結論:貝葉斯是速度很快,但分類效果一般,並且初次訓練之後的結果就很接近算法極限
的算法,幾乎沒有調參的餘地。也就是說,如果我們追求對概率的預測,並且希望越準確越好,那我們應該先選擇邏
輯迴歸。如果數據十分複雜,或者是稀疏矩陣,那我們堅定地使用貝葉斯。如果我們分類的目標不是要追求對概率的
預測,那我們完全可以先試試看高斯樸素貝葉斯的效果(反正它運算很快速,還不需要太多的樣本),如果效果很不
錯,我們就很幸運地得到了一個表現優秀又快速的模型。如果我們沒有得到比較好的結果,那我們完全可以選擇再更
換成更加複雜的模型。
其中的參數結果:
[*zip(range(len(title)),title,model)]
Out[23]:
[(0, 'Naive Bayes', GaussianNB(priors=None, var_smoothing=1e-09)),
(1,
'DecisionTree',
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
max_features=None, max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort=False,
random_state=None, splitter='best')),
(2,
'SVM, RBF kernel',
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape='ovr', degree=3, gamma=0.001, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)),
(3,
'RandomForest',
RandomForestClassifier(bootstrap=True, class_weight=None, criterion='gini',
max_depth=None, max_features='auto', max_leaf_nodes=None,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, n_estimators=50,
n_jobs=None, oob_score=False, random_state=None,
verbose=0, warm_start=False)),
(4,
'Logistic',
LogisticRegression(C=0.1, class_weight=None, dual=False, fit_intercept=True,
intercept_scaling=1, l1_ratio=None, max_iter=100,
multi_class='warn', n_jobs=None, penalty='l2',
random_state=None, solver='lbfgs', tol=0.0001, verbose=0,
warm_start=False))]