python機器學習庫sklearn——樸素貝葉斯分類器
在scikit-learn中,一共有3個樸素貝葉斯的分類演算法類。分別是GaussianNB,MultinomialNB和BernoulliNB。其中GaussianNB就是先驗為高斯分佈的樸素貝葉斯,MultinomialNB就是先驗為多項式分佈的樸素貝葉斯,而BernoulliNB就是先驗為伯努利分佈的樸素貝葉斯。
高斯樸素貝葉斯
GaussianNB 實現了運用於分類的高斯樸素貝葉斯演算法。特徵的可能性(即概率)假設為高斯分佈:
引數
from sklearn import datasets
iris = datasets.load_iris()
from sklearn.naive_bayes import GaussianNB
clf = GaussianNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("高斯樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
多項分佈樸素貝葉斯
MultinomialNB 實現了服從多項分佈資料的樸素貝葉斯演算法,也是用於文字分類(這個領域中資料往往以詞向量表示,儘管在實踐中 tf-idf 向量在預測時表現良好)的兩大經典樸素貝葉斯演算法之一。 分佈引數由每類 y 的 向量決定, 式中 n 是特徵的數量(對於文字分類,是詞彙量的大小) 是樣本中屬於類 y 中特徵 i 概率 。
引數 使用平滑過的最大似然估計法來估計,即相對頻率計數:
式中 是 訓練集 T 中 特徵 i 在類 y 中出現的次數,
是類 y 中出現所有特徵的計數總和。
先驗平滑因子 應用於在學習樣本中沒有出現的特徵,以防在將來的計算中出現0概率輸出。 把 被稱為拉普拉斯平滑(Lapalce smoothing),而被稱為利德斯通(Lidstone smoothing)。
from sklearn import datasets
iris = datasets.load_iris()
from sklearn.naive_bayes import MultinomialNB
clf = MultinomialNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("多項分佈樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
引數說明如下:
alpha:浮點型可選引數,預設為1.0,其實就是新增拉普拉斯平滑,即為上述公式中的λ ,如果這個引數設定為0,就是不新增平滑;
fit_prior:布林型可選引數,預設為True。布林引數fit_prior表示是否要考慮先驗概率,如果是false,則所有的樣本類別輸出都有相同的類別先驗概率。否則可以自己用第三個引數class_prior輸入先驗概率,或者不輸入第三個引數class_prior讓MultinomialNB自己從訓練集樣本來計算先驗概率,此時的先驗概率為P(Y=Ck)=mk/m。其中m為訓練集樣本總數量,mk為輸出為第k類別的訓練集樣本數。
class_prior:可選引數,預設為None。
總結如下:
fit_prior class_prior 最終先驗概率
False 填或不填沒有意義 P(Y = Ck) = 1 / k
True 不填 P(Y = Ck) = mk / m
True 填 P(Y = Ck) = class_prior
伯努利樸素貝葉斯
BernoulliNB 實現了用於多重伯努利分佈資料的樸素貝葉斯訓練和分類演算法,即有多個特徵,但每個特徵 都假設是一個二元 (Bernoulli, boolean) 變數。 因此,這類演算法要求樣本以二元值特徵向量表示;如果樣本含有其他型別的資料, 一個 BernoulliNB 例項會將其二值化(取決於 binarize 引數)。
伯努利樸素貝葉斯的決策規則基於
與多項分佈樸素貝葉斯的規則不同 伯努利樸素貝葉斯明確地懲罰類 y 中沒有出現作為預測因子的特徵 i ,而多項分佈分佈樸素貝葉斯只是簡單地忽略沒出現的特徵。
在文字分類的例子中,詞頻向量(word occurrence vectors)(而非詞數向量(word count vectors))可能用於訓練和用於這個分類器。 BernoulliNB 可能在一些資料集上可能表現得更好,特別是那些更短的文件。 如果時間允許,建議對兩個模型都進行評估。
from sklearn import datasets
iris = datasets.load_iris()
from sklearn.naive_bayes import BernoulliNB
clf = BernoulliNB()
clf = clf.fit(iris.data, iris.target)
y_pred=clf.predict(iris.data)
print("伯努利樸素貝葉斯,樣本總數: %d 錯誤樣本數 : %d" % (iris.data.shape[0],(iris.target != y_pred).sum()))
堆外樸素貝葉斯模型擬合
樸素貝葉斯模型可以解決整個訓練集不能匯入記憶體的大規模分類問題。 為了解決這個問題, MultinomialNB, BernoulliNB, 和 GaussianNB 實現了 partial_fit 方法,可以動態的增加資料,使用方法與其他分類器的一樣。所有的樸素貝葉斯分類器都支援樣本權重。
文件貝葉斯分類器案例
對於新聞分類,屬於多分類問題。我們可以使用MultinamialNB()完成我們的新聞分類問題。
import numpy as np
"""
這個指南的目的是在一個實際任務上探索scikit-learn的主要工具,在二十個不同的主題上分析一個文字集合。
在這一節中,可以看到:
1、載入文字檔案和類別
2、適合機器學習的特徵向量提取
3、訓練線性模型進行分類
4、使用網格搜尋策略,找到一個很好的配置的特徵提取元件和分類器
"""
"""
1、Loading the 20 newsgroups dataset 載入20個新聞組資料集
為了獲得更快的執行時間為第一個例子,我們將工作在部分資料集只有4個類別的資料集中:
"""
categories = ['alt.atheism', 'soc.religion.christian', 'comp.graphics', 'sci.med']
from sklearn.datasets import fetch_20newsgroups
twenty_train = fetch_20newsgroups(subset='train', categories=categories, shuffle=True, random_state=42)
print(twenty_train.target)
print(twenty_train.target_names) # 訓練集中類別的名字,這裡只有四個類別
print(len(twenty_train.data)) # 訓練集中資料的長度
print(len(twenty_train.filenames)) # 訓練集檔名長度
print('-----')
print("\n".join(twenty_train.data[0].split("\n")[:3]))
print('-----')
print(twenty_train.target_names[twenty_train.target[0]])
print('-----')
print(twenty_train.target[:10]) # 前十個的類別
print('-----')
for t in twenty_train.target[:10]:
print(twenty_train.target_names[t]) # 類別的名字
print('-----')
"""
2、Extracting features from text files 從文字檔案中提取特徵
為了在文字檔案中使用機器學習演算法,首先需要將文字內容轉換為數值特徵向量
"""
"""
Bags of words 詞袋
最直接的方式就是詞袋錶示法
1、為訓練集的任何文件中的每個單詞分配一個固定的整數ID(例如通過從字典到整型索引建立字典)
2、對於每個文件,計算每個詞出現的次數,並存儲到X[i,j]中。
詞袋錶示:n_features 是語料中不同單詞的數量,這個數量通常大於100000.
如果 n_samples == 10000,儲存X的陣列就需要10000*10000*4byte=4GB,這麼大的儲存在今天的計算機上是不可能實現的。
幸運的是,X中的大多數值都是0,基於這種原因,我們說詞袋是典型的高維稀疏資料集,我們可以只儲存那些非0的特徵向量。
scipy.sparse 矩陣就是這種資料結構,而scikit-learn內建了這種資料結構。
"""
"""
Tokenizing text with scikit-learn 使用scikit-learn標記文字
文字處理、分詞、過濾停用詞都在這些高階元件中,能夠建立特徵字典並將文件轉換成特徵向量。
"""
from sklearn.feature_extraction.text import CountVectorizer # sklearn中的文字特徵提取元件中,匯入特徵向量計數函式
count_vect = CountVectorizer() # 特徵向量計數函式
X_train_counts = count_vect.fit_transform(twenty_train.data) # 對文字進行特徵向量處理
print(X_train_counts) # 特徵向量和特徵標籤
print(X_train_counts.shape) # 形狀
print('-----')
"""
CountVectorizer支援計算單詞或序列的N-grams,一旦合適,這個向量化就可以建立特徵詞典。
在整個訓練預料中,詞彙中的詞彙索引值與其頻率有關。
"""
print(count_vect.vocabulary_.get(u'algorithm'))
print('-----')
"""
From occurrences to frequencies 從事件到頻率
計數是一個好的開始,但是也存在一個問題:較長的文字將會比較短的文字有很高的平均計數值,即使他們所表示的話題是一樣的。
為了避免潛在的差異,它可以將文件中的每個單詞出現的次數在文件的總字數的比例:這個新的特徵叫做詞頻:tf
tf-idf:詞頻-逆文件頻率
"""
from sklearn.feature_extraction.text import TfidfTransformer # sklearn中的文字特徵提取元件中,匯入詞頻統計函式
tf_transformer = TfidfTransformer(use_idf=False).fit(X_train_counts) # 建立詞頻統計函式,注意這裡idf=False
print(tf_transformer) # 輸出函式屬性 TfidfTransformer(norm=u'l2', smooth_idf=True, sublinear_tf=False, use_idf=False)
print('-----')
X_train_tf = tf_transformer.transform(X_train_counts) # 使用函式對文字文件進行tf-idf頻率計算
print(X_train_tf)
print('-----')
print(X_train_tf.shape)
print('-----')
"""
在上面的例子中,使用fit()方法來構建基於資料的預測器,然後使用transform()方法來將計數矩陣用tf-idf表示。
這兩個步驟可以通過跳過冗餘處理,來更快的達到相同的最終結果。
這些可以通過使用fit_transform()方法來實現:
"""
tfidf_transformer = TfidfTransformer() # 這裡使用的是tf-idf
X_train_tfidf = tfidf_transformer.fit_transform(X_train_counts)
print(X_train_tfidf)
print(X_train_tfidf.shape)
print('-----')
"""
Training a classifier 訓練一個分類器
既然已經有了特徵,就可以訓練分類器來試圖預測一個帖子的類別,先使用貝葉斯分類器,貝葉斯分類器提供了一個良好的基線來完成這個任務。
scikit-learn中包括這個分類器的許多變數,最適合進行單詞計數的是多項式變數。
"""
from sklearn.naive_bayes import MultinomialNB # 使用sklearn中的貝葉斯分類器,並且載入貝葉斯分類器
# 中的MultinomialNB多項式函式
clf = MultinomialNB() # 載入多項式函式
x_clf = clf.fit(X_train_tfidf, twenty_train.target) # 構造基於資料的分類器
print(x_clf) # 分類器屬性:MultinomialNB(alpha=1.0, class_prior=None, fit_prior=True)
print('-----')
"""
為了預測輸入的新的文件,我們需要使用與前面相同的特徵提取鏈進行提取特徵。
不同的是,在轉換中,使用transform來代替fit_transform,因為訓練集已經構造了分類器
"""
docs_new = ['God is love', 'OpenGL on the GPU is fast'] # 文件
X_new_counts = count_vect.transform(docs_new) # 構建文件計數
X_new_tfidf = tfidf_transformer.transform(X_new_counts) # 構建文件tfidf
predicted = clf.predict(X_new_tfidf) # 預測文件
print(predicted) # 預測類別 [3 1],一個屬於3類,一個屬於1類
for doc, category in zip(docs_new, predicted):
print('%r => %s' % (doc, twenty_train.target_names[category])) # 將文件和類別名字對應起來
print('-----')
"""
Building a pipeline 建立管道
為了使向量轉換更加簡單(vectorizer => transformer => classifier),scikit-learn提供了pipeline類來表示為一個複合分類器
"""
from sklearn.pipeline import Pipeline
text_clf = Pipeline([('vect', CountVectorizer()), ('tfidf', TfidfTransformer()), ('clf', MultinomialNB())])
text_clf = text_clf.fit(twenty_train.data, twenty_train.target)
print(text_clf) # 構造分類器,分類器的屬性
predicted = text_clf.predict(docs_new) # 預測新文件
print(predicted) # 獲取預測值
print('-----')
"""
分析總結:
1、載入資料集,主要是載入訓練集,用於對資料進行訓練
2、文字特徵提取:
對文字進行計數統計 CountVectorizer
詞頻統計 TfidfTransformer (先計算tf,再計算tfidf)
3、訓練分類器:
貝葉斯多項式訓練器 MultinomialNB
4、預測文件:
通過構造的訓練器進行構造分類器,來進行文件的預測
5、最簡單的方式:
通過使用pipeline管道形式,來講上述所有功能通過管道來一步實現,更加簡單的就可以進行預測
"""
"""
Evaluation of the performance on the test set 測試集效能評價
評估模型的預測精度同樣容易:
"""
import numpy as np
twenty_test = fetch_20newsgroups(subset='test', categories=categories, shuffle=True, random_state=42)
docs_test = twenty_test.data
predicted = text_clf.predict(docs_test)
print(np.mean(predicted == twenty_test.target)) # 預測的值和測試值的比例,mean就是比例函式
print('-----') # 精度已經為0.834886817577
"""
精度已經實現