【火爐煉AI】機器學習010-用樸素貝葉斯分類器解決多分類問題

煉丹老頑童發表於2018-08-06

【火爐煉AI】機器學習010-用樸素貝葉斯分類器解決多分類問題

(本文所使用的Python庫和版本號: Python 3.5, Numpy 1.14, scikit-learn 0.19, matplotlib 2.2 )

前面講到了使用邏輯迴歸分類器解決多分類問題(【火爐煉AI】機器學習009-用邏輯迴歸分類器解決多分類問題 ),但是解決多分類問題並不是只有邏輯迴歸一種方法,此處我們講解用樸素貝葉斯分類器來解決多分類問題。

樸素貝葉斯的“樸素”,並不是簡單的意思,而是指樣本的特徵之間是相互獨立的。在所有的機器學習分類演算法中,樸素貝葉斯和其他絕大部分分類演算法都不同,其他分類演算法基本都是判別方法,即直接學習出特徵輸出Y和特徵向量X之間的關係,要麼是決策函式Y=f(X),要麼是條件分佈P(Y|X),但是樸素貝葉斯卻是生成方法,也就是直接找出特徵輸出Y和特徵向量X之間的聯合分佈P(X,Y),然後用P(Y|X)=P(X,Y)/P(X)得出。

樸素貝葉斯的優點在於:1,有穩定的分類效率,2,對小規模資料表現很好,能處理多分類任務,適合增量式訓練,尤其是資料量超出記憶體時,可以一批一批的去增量訓練。3,對缺失資料不太敏感,演算法比較簡單,常用於文字分類。

但樸素貝葉斯的缺點是:1,樸素貝葉斯演算法有一個重要的使用前提:樣本的特徵屬性之間是相互獨立的,這使得樸素貝葉斯演算法在滿足這一條件的資料集上效果非常好,而不滿足獨立性條件的資料集上,效果欠佳。理論上,樸素貝葉斯模型與其他分類方法相比,有最小的誤差率,但是這一結果僅限於滿足獨立性條件的資料集上。在實際應用中,屬性之間不太可能完全獨立,特別是在特徵屬性個數非常多,且屬性之間相關性較大時,樸素貝葉斯分類效果不太好。2,需要知道先驗概率,且先驗概率很多時候取決於假設,假設的模型可以有很多種,因此在某些時候會由於假設的先驗模型的原因導致預測效果不佳。3,由於通過先驗和資料來決定後驗的概率從而決定分類,所以分類決策存在一定的錯誤率。4,對輸入資料的表達形式很敏感。

關於樸素貝葉斯模型的數學推導,可以參考:https://blog.csdn.net/malele4th/article/details/79348473


1. 準備資料集

本專案所使用的資料集參考《Python機器學習經典例項》中第二章提供的data_multivar資料集,下面是載入並分析該資料集的程式碼。

# 準備資料集
data_path='D:\PyProjects\DataSet/NaiveBayers/data_multivar.txt'
df=pd.read_csv(data_path,header=None)
# print(df.head())
# print(df.info()) # 檢視資料資訊,確保沒有錯誤
dataset_X,dataset_y=df.iloc[:,:-1],df.iloc[:,-1] # 拆分為X和Y
# print(dataset_X.head())
# print(dataset_X.info())
# print('-'*100)
# print(dataset_y.head())
dataset_X=dataset_X.values
dataset_y=dataset_y.values
# print(dataset_X.shape) # (400, 2)
# print(dataset_y.shape) # (400,)
classes=list(set(dataset_y)) 
print('class Num: {}, class: {}'.format(len(classes), classes))
# 上面檢查載入沒有問題,一共有四個不同類別,類別名稱為:0,1,2,3
複製程式碼

-------------------------------------輸---------出--------------------------------

class Num: 4, class: [0, 1, 2, 3]

--------------------------------------------完-------------------------------------

上面從txt檔案中載入了資料集,可以看出,該資料集含有400個樣本,被平均分成4個不同類別(0,1,2,3)。下面將這不同類別的資料集繪製到散點圖中,以觀察每個類別的大概聚集位置。

# 資料集視覺化
def visual_2D_dataset(dataset_X,dataset_y):
    '''將二維資料集dataset_X和對應的類別dataset_y顯示在散點圖中'''
    assert dataset_X.shape[1]==2,'only support dataset with 2 features'
    plt.figure()
    classes=list(set(dataset_y)) 
    markers=['.',',','o','v','^','<','>','1','2','3','4','8'
             ,'s','p','*','h','H','+','x','D','d','|']
    colors=['b','c','g','k','m','w','r','y']
    for class_id in classes:
        one_class=np.array([feature for (feature,label) in 
                   zip(dataset_X,dataset_y) if label==class_id])
        plt.scatter(one_class[:,0],one_class[:,1],marker=np.random.choice(markers,1)[0],
                    c=np.random.choice(colors,1)[0],label='class_'+str(class_id))
    plt.legend()

visual_2D_dataset(dataset_X,dataset_y)
複製程式碼

該資料集的類別分佈圖

########################小**********結###############################

1,資料集的準備,分析,視覺化等常常是機器學習的第一步,也是非常重要的一個部分,更是非常耗時的一個部分。

2,此處定義了一個資料集視覺化函式,用於將具有兩個特徵屬性的資料集按照不同類別繪製到散點圖中。

#################################################################


2. 構建樸素貝葉斯分類器模型

在sklearn模組中,一共有三個樸素貝葉斯分類方法,分別是GaussianNB, MultinomialNB和BernouliNB,其中,GaussianNB是先驗為高斯分佈的樸素貝葉斯,適用於樣本特徵的分佈大部分是連續值的情況;MultinomialNB是先驗為多項式分佈的樸素貝葉斯,適用於樣本特徵的分佈大部分是多元離散值的情況;BernouliNB是先驗為伯努利分佈的樸素貝葉斯,適用於樣本特徵是二元離散值或者很稀疏的多元離散值的情況。下面我分別用這三個分類方法來解決本專案的分類問題。

2.1 使用GaussianNB分類器構建樸素貝葉斯模型

直接上程式碼,構建模型後還測試了一下該模型在整個資料集上的表現:

# 使用GaussianNB分類器構建樸素貝葉斯模型
from sklearn.naive_bayes import GaussianNB
gaussianNB=GaussianNB()
gaussianNB.fit(dataset_X,dataset_y)

# 評估本模型在整個資料集上的表現
dataset_predict_y=gaussianNB.predict(dataset_X)
correct_predicts=(dataset_predict_y==dataset_y).sum()
accuracy=100*correct_predicts/dataset_y.shape[0]
print('GaussianNB, correct prediction num: {}, accuracy: {:.2f}%'
      .format(correct_predicts,accuracy))

plot_classifier(gaussianNB,dataset_X,dataset_y)
複製程式碼

-------------------------------------輸---------出--------------------------------

GaussianNB, correct prediction num: 398, accuracy: 99.50%

--------------------------------------------完-------------------------------------

GaussianNB分類器分類結果

2.2 使用MultinomialNB分類器構建樸素貝葉斯模型

很可惜,貌似MultinomialNB分類器要求資料集的所有特徵屬性都是非負數,否則沒法訓練。故而下面的程式碼報錯。

# 使用MultinomialNB分類器構建樸素貝葉斯模型
from sklearn.naive_bayes import MultinomialNB
multinomialNB=MultinomialNB()
multinomialNB.fit(dataset_X,dataset_y) 
# 此處報錯,multinomialNB的資料集的特徵屬性必須是非負數

# 評估本模型在整個資料集上的表現
dataset_predict_y_multi=multinomialNB.predict(dataset_X)
correct_predicts_multi=(dataset_predict_y_multi==dataset_y).sum()
accuracy=100*correct_predicts_multi/dataset_y.shape[0]
print('MultinomialNB, correct prediction num: {}, accuracy: {:.2f}%'
      .format(correct_predicts,accuracy))
複製程式碼

-------------------------------------輸---------出--------------------------------

ValueError: Input X must be non-negative

--------------------------------------------完-------------------------------------

2.3 使用BernouliNB分類器構建樸素貝葉斯模型

構建和測試方法與GaussianNB幾乎一樣,程式碼為:


# 使用BernouliNB分類器構建樸素貝葉斯模型
from sklearn.naive_bayes import BernoulliNB
bernoulliNB=BernoulliNB()
bernoulliNB.fit(dataset_X,dataset_y) 

# 評估本模型在整個資料集上的表現
dataset_predict_y_bern=bernoulliNB.predict(dataset_X)
correct_predicts_bern=(dataset_predict_y_bern==dataset_y).sum()
accuracy=100*correct_predicts_bern/dataset_y.shape[0]
print('BernoulliNB, correct prediction num: {}, accuracy: {:.2f}%'
      .format(correct_predicts_bern,accuracy))

plot_classifier(bernoulliNB,dataset_X,dataset_y)
複製程式碼

-------------------------------------輸---------出--------------------------------

BernoulliNB, correct prediction num: 195, accuracy: 48.75%

--------------------------------------------完-------------------------------------

使用BernouliNB分類器得到的分類結果

########################小**********結###############################

1,雖然sklearn模組中有三種樸素貝葉斯方法,但在同一個資料集上的表現卻大不相同,只有GaussianNB表現最好,能夠正確的將四個資料集區分開來。

2,此處定義了一個資料集視覺化函式,用於將具有兩個特徵屬性的資料集按照不同類別繪製到散點圖中,對於其他專案這個函式也可以直接使用。

3,這三種樸素貝葉斯方法中,MultinomialNB要求資料集中的特徵向量數值必須為非負數,否則直接報錯。BernoulliNB雖然沒有報錯,但是從分類結果圖中可以看到,結果非常不理想,可以說完全沒有起到分類的效果。

#################################################################


注:本部分程式碼已經全部上傳到(我的github)上,歡迎下載。

參考資料:

1, Python機器學習經典例項,Prateek Joshi著,陶俊傑,陳小莉譯

相關文章