【机器学习入门】(2) 朴素贝叶斯算法:原理、实例应用(文档分类预测)附python完整代码及数据集
各位同學(xué)好,今天我向大家介紹python機(jī)器學(xué)習(xí)中的樸素貝葉斯算法。內(nèi)容有:算法的基本原理;案例實(shí)戰(zhàn)--新聞文檔的分類預(yù)測(cè)。
案例簡(jiǎn)介:新聞數(shù)據(jù)有20個(gè)主題,有10萬多篇文章,每篇文章對(duì)應(yīng)不同的主題,要求是任意輸入一篇新的文章,模型輸出這篇文章屬于哪個(gè)主題。
1. 算法原理
1.1 樸素貝葉斯方法
樸素貝葉斯方法涉及一些概率論知識(shí),我們先來復(fù)習(xí)一下。
聯(lián)合概率:包含多個(gè)條件,并且所有的條件同時(shí)成立的概率,公式為:
條件概率:事件A在另一個(gè)事件B已經(jīng)發(fā)生的前提下發(fā)生的概率,記作P(A|B),如果有多個(gè)條件,
那記作:
樸素貝葉斯一般公式:
我舉個(gè)小例子幫助大家理解:
某學(xué)校有N名學(xué)生,男生占60%,女生占40%。男生都留短發(fā),女生一半留短發(fā),一半留長(zhǎng)發(fā)。
問題1:隨機(jī)一個(gè)學(xué)生,知道性別的情況下,他(她)留短發(fā)的概率是多少??
答:男:P(短發(fā)|男生)=1;女:P(短發(fā)|女生)=0.5
問題2:隨機(jī)一個(gè)學(xué)生,只知道他留短發(fā),他是男生的概率是多少?
答:設(shè) B=短發(fā);A=男生
要求的是?
P(B|A)=1, P(A)=0.6, P(B)=0.6*1+0.4*0.5=0.8
P(A|B)=1*0.6/0.8=0.75
1.2 文檔分類方法
文檔分類是在已經(jīng)分類好了的文檔中提取關(guān)鍵字,在以后遇到新的文檔時(shí),從這些關(guān)鍵字中預(yù)測(cè)這篇新文章是哪個(gè)類別。
在文檔分類中,樸素貝葉斯公式為:
P(C|W)?:某個(gè)關(guān)鍵字屬于某個(gè)分類的概率
P(W|C)?:某個(gè)分類下,某個(gè)關(guān)鍵字出現(xiàn)的概率
P(C) :? ? ?某個(gè)類別的概率(某個(gè)類別的文檔數(shù)/總文檔數(shù))
P(W) :??? 這個(gè)關(guān)鍵字在需要預(yù)測(cè)的文檔中出現(xiàn)的概率
1.3 拉普拉斯平滑系數(shù)
? ? ? ?假如現(xiàn)在有一新的篇文章,它的主題包括‘影院’‘云計(jì)算’等關(guān)鍵字,我計(jì)算它屬于娛樂類文章的概率。公式如下:
P(娛樂類|影院,云計(jì)算) = P(影院,云計(jì)算|娛樂類)*P(娛樂類)/P(影院,云計(jì)算),
其中P(影院,云計(jì)算|科技類)=P(影院|科技類)* P(云計(jì)算|科技類)
? ? ? ?然而對(duì)于預(yù)測(cè)之前建立的分類模型,如果在已經(jīng)分類好的文章中娛樂類文章種沒有出現(xiàn)過云計(jì)算這個(gè)關(guān)鍵字,那么P(云計(jì)算|娛樂類)=0,導(dǎo)致P(影院,云計(jì)算|娛樂類)=0,結(jié)果就是一篇包括‘影院’‘云計(jì)算’等關(guān)鍵字的文章屬于娛樂類的概率為0,這肯定不對(duì)。只要它里面包含了任何一個(gè)和娛樂類相關(guān)的詞,都有可能是娛樂類。
?????? 因此引入拉普拉斯平滑系數(shù)來避免出現(xiàn)0概率的情況。方法如下:
將 P(W|C) 更改為?
Ni:該W詞在C類別所有文檔中出現(xiàn)的次數(shù),即云計(jì)算在娛樂類文章中出現(xiàn)了多少次。
N: C類別的文檔所有詞出現(xiàn)的次數(shù)和,即娛樂類一共有多少詞。
a: 指定系數(shù),一般為1。
m:訓(xùn)練文檔中統(tǒng)計(jì)出現(xiàn)的特征詞個(gè)數(shù),即整個(gè)文檔有多少詞。
1.4 特征向量化方法
將一篇文章中出現(xiàn)的所有詞進(jìn)行特征向量化,將單詞提取出來,計(jì)算它們一共出現(xiàn)了多少次。首先要從sklearn庫中導(dǎo)入該方法?from sklearn.feature_extraction.text import CountVectorizer。
特征向量化方法:vect.fit_transform()
上式可理解為:fit表示提取特征,transform表示變成sparss矩陣
下面我用兩個(gè)字符串例子來演示一下這個(gè)方法:
# 導(dǎo)入特征向量化方法
from sklearn.feature_extraction.text import CountVectorizer
# 定義兩個(gè)字符串
word1 = 'i love python, python makes me happy'
word2 = 'hello world, i love the world'
# 變量vect接收特征向量化方法
vect = CountVectorizer()
# 將2個(gè)變量傳入特征向量化方法,用于提取每個(gè)單詞出現(xiàn)的次數(shù)
words = vect.fit_transform([word1,word2])
words變量接收的是sprase類型的矩陣,sparse矩陣只會(huì)標(biāo)記word1和word2中不為0的地方,為0的地方不顯示,即空格符就不計(jì)數(shù)直接跳過。如'i','love'等詞,sparse矩陣會(huì)對(duì)這些詞進(jìn)行標(biāo)記,標(biāo)記方式為該詞出現(xiàn)的次數(shù)。下面用代碼幫助大家理解。
使用?vect.get_feature_names()?命令來獲取word1和word2中出現(xiàn)的所有單詞。
使用 .toarray() 將sparse矩陣轉(zhuǎn)換成正常的數(shù)組形式,便于觀察
# 查看提取了哪些單詞
names = vect.get_feature_names() #提取word1和word2中出現(xiàn)過的所有單詞
# 將sparse矩陣轉(zhuǎn)換成正常的數(shù)組形式
arr = words.toarray()
解釋:arr變量中第0行表示word1某單詞出現(xiàn)次數(shù),第1行表示word2,某出現(xiàn)次數(shù)與names列表中的對(duì)應(yīng)。即name列表中的'happy'在word1中出現(xiàn)了1次,在word2中出現(xiàn)了0次,‘world’這個(gè)詞在word1中出現(xiàn)了0次,在word2中出現(xiàn)了2次。
2. 文檔分類實(shí)戰(zhàn)
2.1 數(shù)據(jù)獲取
? ? ? ?使用sklearn內(nèi)部數(shù)據(jù)集獲取新聞分組數(shù)據(jù),下載到指定文件夾。有關(guān)系統(tǒng)內(nèi)部數(shù)據(jù)集的獲取方法可以參考我的前一篇文章機(jī)器學(xué)習(xí)-K近鄰算法,或者該網(wǎng)頁sklearn數(shù)據(jù)集,本篇文章就不進(jìn)行詳述。如果找不到數(shù)據(jù)集的,文末有數(shù)據(jù)集,有需要的自取。
# 使用sklearn內(nèi)部數(shù)據(jù)集,獲取新聞分組數(shù)據(jù)
from sklearn.datasets import fetch_20newsgroups
# 指定文件下載位置,把新聞數(shù)據(jù)下載到里面
filepath = 'C:\\Users\\admin\\.spyder-py3\\test\\文件處理\\newsgroup'
newsgroups = fetch_20newsgroups(data_home = filepath) #返回值是一個(gè).Bunch類型數(shù)據(jù)
? ? ? ?我們得到的newsgroups是一個(gè).Bunch類型的數(shù)據(jù);data中存放的是11314篇新聞文章;DESCR是對(duì)這個(gè)數(shù)據(jù)集的描述;filename是文件路徑,可以忽視;target存放的是這11314篇文章的分類,一共有20個(gè)類別記作0到19;target_names記錄的是20種分類的名稱。
2.2 數(shù)據(jù)處理
? ? ? ? 首先從.Bunch數(shù)據(jù)中提取我們需要的,news_data相當(dāng)于預(yù)測(cè)所需的特征值x,news_target相當(dāng)于預(yù)測(cè)目標(biāo)y。
# news_data中存放具體的文章,相當(dāng)于x
news_data = newsgroups.data
# news_target中存放數(shù)據(jù)的目標(biāo)值,即分類的結(jié)果,相當(dāng)于y
news_target = newsgroups.target
? ? ? ? 從數(shù)據(jù)中提取最后10行用于結(jié)果驗(yàn)證,news_predict_data 存放最后十個(gè)的文章數(shù)據(jù),用作最后預(yù)測(cè)函數(shù)的輸入值,news_predict_target 存放最后十個(gè)主題分類,用于和最終預(yù)測(cè)結(jié)果比較,驗(yàn)證是否正確。然后將建模所用的數(shù)據(jù)剔除最后10行,即將?news_data?和?news_target?都刪除最后10行數(shù)據(jù)。
# 取最后10行特征值作為驗(yàn)證集。用于預(yù)測(cè)的x
news_predict_data = news_data[-10:]
# 最后10行目標(biāo)作為驗(yàn)證預(yù)測(cè)結(jié)果的準(zhǔn)確性。用于驗(yàn)證的y
news_predict_target = news_target[-10:]
# 用于建模的特征值刪除最后10行,x
news_data = news_data[:-10]
# 用于建模的目標(biāo)值刪除最后10行,y
news_target = news_target[:-10]
到此我們已經(jīng)劃分出驗(yàn)證所用數(shù)據(jù)和建模所用數(shù)據(jù)。
2.3 劃分訓(xùn)練集和測(cè)試集
一般采用75%的數(shù)據(jù)用于訓(xùn)練,25%用于測(cè)試,因此把數(shù)據(jù)進(jìn)行訓(xùn)練之前,先要對(duì)數(shù)據(jù)劃分。
使用?sklearn.model_selection.train_test_split 進(jìn)行分割
劃分方式:
x_train,x_test,y_train,y_test = train_test_split(x數(shù)據(jù),y數(shù)據(jù),test_size=數(shù)據(jù)占比)
train_test_split() 參數(shù)
x:數(shù)據(jù)集特征值(news_data)
y:數(shù)據(jù)集目標(biāo)值(news_target)
test_size: 測(cè)試數(shù)據(jù)占比,用小數(shù)表示
train_test_split() 返回值
x_train:訓(xùn)練部分特征值
x_test:?測(cè)試部分特征值
y_train:訓(xùn)練部分目標(biāo)值
y_test: 測(cè)試部分目標(biāo)值
# 劃分測(cè)試集和訓(xùn)練集
from sklearn.model_selection import train_test_split
# 數(shù)據(jù)的75%用于訓(xùn)練,25%用于測(cè)試
x_train,x_test,y_train,y_test = train_test_split(news_data,news_target,test_size=0.25)
2.4 特征提取
? ? ? ?為了統(tǒng)計(jì)每一篇文章中各個(gè)單詞出現(xiàn)的次數(shù),哪些分類中哪些單詞出現(xiàn)的比較多,從而建立分類模型,同1.4所述。因此導(dǎo)入特征向量化方法CountVectorizer()
? ? ? ? 然后,對(duì)用于訓(xùn)練的新聞數(shù)據(jù) x_train?進(jìn)行 .fit_transform() 操作,先進(jìn)行fit提取特征值,再transform 將數(shù)據(jù)sparse矩陣化,統(tǒng)計(jì)各個(gè)單詞出現(xiàn)次數(shù),特征向量化方法見1.4。
? ? ? ?那么為什么對(duì)于測(cè)試用的新聞數(shù)據(jù) x_test 只需要進(jìn)行?transform?操作,而不需要 fit 提取特征值呢?可以簡(jiǎn)單理解為,x_train?是用來建立模型的,我需要知道它有哪些特征,這些特征值如何與目標(biāo)值 y_train 相對(duì)應(yīng)。模型建立完成之后,測(cè)試數(shù)據(jù) x_test 是用來檢測(cè)這個(gè)模型的準(zhǔn)確率,相當(dāng)于我給這個(gè)模型傳一個(gè) sparse 矩陣,這么模型自己就會(huì)進(jìn)行一個(gè)特征的提取,內(nèi)部會(huì)對(duì)我對(duì)輸入值進(jìn)行一系列處理得到預(yù)測(cè)結(jié)果。同理,我們也需要對(duì)驗(yàn)證所用的x數(shù)據(jù) news_predict_data 進(jìn)行sparse矩陣化。
# 導(dǎo)入特征向量化方法
from sklearn.feature_extraction.text import CountVectorizer
# news_vect 接收特征向量化方法
news_vect = CountVectorizer()
# 將x_train傳入特征向量化方法
x_train = news_vect.fit_transform(x_train) #用于訓(xùn)練
# 測(cè)試數(shù)據(jù)矩陣化
x_test = news_vect.transform(x_test) #用于測(cè)試
# 把驗(yàn)證數(shù)據(jù)變成sparss矩陣,輸入sparss矩陣,輸出預(yù)測(cè)結(jié)果
news_predict_data = news_vect.transform(news_predict_data)
2.5 樸素貝葉斯方法預(yù)測(cè)
首先導(dǎo)入樸素貝葉斯方法庫 from sklearn.naive_bayes import MultinomialNB
樸素貝葉斯函數(shù):??MultinomialNB()
MultinomialNB() 接收的參數(shù) (alpha=1,fit_prior=True,class_prior=None)
alpha:拉普拉斯平滑系數(shù),默認(rèn)為1
樸素貝葉斯訓(xùn)練方法:??.fit(self, x_train, y_train, sample_weight=None)
傳入的x可以是數(shù)組、列表、sparss矩陣
# 導(dǎo)入樸素貝葉斯方法
from sklearn.naive_bayes import MultinomialNB
# nb接收樸素貝葉斯方法
nb = MultinomialNB()
# 訓(xùn)練,傳入訓(xùn)練的特征sparss矩陣,訓(xùn)練的目標(biāo)值
nb.fit(x_train,y_train)
# 評(píng)分法看模型準(zhǔn)確率,傳入測(cè)試值特征sparss矩陣,和測(cè)試目標(biāo)值
accuracy = nb.score(x_test,y_test)
# 預(yù)測(cè),輸入預(yù)測(cè)所需的特征值x
result = nb.predict(news_predict_data)
評(píng)分法計(jì)算模型準(zhǔn)確率:? .score(x_test, y_test)
根據(jù)x_test預(yù)測(cè)結(jié)果,把預(yù)測(cè)結(jié)果和真實(shí)的y_test比較,計(jì)算準(zhǔn)確率
樸素貝葉斯預(yù)測(cè)方法:? .predict(預(yù)測(cè)所需的x數(shù)據(jù))
此處的x數(shù)據(jù)需要輸入sparse矩陣
accuracy 存放模型準(zhǔn)確率,result?存放分類結(jié)果,最終準(zhǔn)確率為83%,result和實(shí)際結(jié)果news_predict_target有微小偏差。
新聞數(shù)據(jù)集自取:
https://download.csdn.net/download/dgvv4/41914595
完整代碼如下,只需更改filepath文件下載路徑即可運(yùn)行
# 文檔分類實(shí)戰(zhàn)#(1)數(shù)據(jù)獲取
# 使用sklearn內(nèi)部數(shù)據(jù)集,獲取新聞分組數(shù)據(jù)
from sklearn.datasets import fetch_20newsgroups
# 指定文件下載位置,把新聞數(shù)據(jù)下載到里面
filepath = 'C:\\Users\\admin\\.spyder-py3\\test\\文件處理\\newsgroup'
newsgroups = fetch_20newsgroups(data_home = filepath) #返回值是一個(gè).Bunch類型數(shù)據(jù)#(2)數(shù)據(jù)預(yù)處理
# news_names存放分類,一共20類
news_names = newsgroups.target_names
# news_data中存放具體的文章,相當(dāng)于x
news_data = newsgroups.data
# news_target中存放數(shù)據(jù)的目標(biāo)值,即分類的結(jié)果,相當(dāng)于y
news_target = newsgroups.target# 取最后10行特征值作為驗(yàn)證集。用于預(yù)測(cè)的x
news_predict_data = news_data[-10:]
# 最后10行目標(biāo)作為驗(yàn)證預(yù)測(cè)結(jié)果的準(zhǔn)確性。用于驗(yàn)證的y
news_predict_target = news_target[-10:]
# 用于建模的特征值刪除最后10行,x
news_data = news_data[:-10]
# 用于建模的目標(biāo)值刪除最后10行,y
news_target = news_target[:-10]#(3)劃分測(cè)試集和訓(xùn)練集
from sklearn.model_selection import train_test_split
# 數(shù)據(jù)的75%用于訓(xùn)練,25%用于測(cè)試
x_train,x_test,y_train,y_test = train_test_split(news_data,news_target,test_size=0.25)#(4)特征抽取
# 導(dǎo)入特征向量化方法
from sklearn.feature_extraction.text import CountVectorizer
news_vect = CountVectorizer() # news_vect 接收特征向量化方法
# 將x_train傳入特征向量化方法,用于統(tǒng)計(jì)x_train中每篇文章的單詞出現(xiàn)了多少次,返回sparss矩陣
# fit先提取x_train的特征,transform將x_train中的數(shù)據(jù)進(jìn)行sparss矩陣化
x_train = news_vect.fit_transform(x_train) #用于訓(xùn)練
# 上面已經(jīng)進(jìn)行過提取特征的操作,這一步不需要fit,直接進(jìn)行transform矩陣化即可
x_test = news_vect.transform(x_test) #用于測(cè)試,我給模型一個(gè)sparss矩陣,模型給我一個(gè)預(yù)測(cè)結(jié)果
# 同理,我也需要把驗(yàn)證數(shù)據(jù)變成sparss矩陣,輸入sparss矩陣,輸出預(yù)測(cè)結(jié)果
news_predict_data = news_vect.transform(news_predict_data) #(5)樸素貝葉斯方法預(yù)測(cè)
from sklearn.naive_bayes import MultinomialNB # 導(dǎo)入樸素貝葉斯方法
# MultinomialNB接收的參數(shù)(alpha=1,fit_prior=True,class_prior=None)
# alpha:拉普拉斯平滑系數(shù),默認(rèn)為1
# 用于訓(xùn)練時(shí)的fit()方法,fit(self,x,y,sample_weight=None)
# 傳入的x可以是數(shù)組、列表、sparss矩陣nb = MultinomialNB() # nb接收樸素貝葉斯方法
# 訓(xùn)練,傳入訓(xùn)練的特征sparss矩陣,訓(xùn)練的目標(biāo)值
# 樸素貝葉斯訓(xùn)練時(shí),只需要提取特征值fit,不需要transform對(duì)特征進(jìn)行一系列操作
nb.fit(x_train,y_train)
# 評(píng)分法看模型準(zhǔn)確率,傳入測(cè)試值特征sparss矩陣,和測(cè)試目標(biāo)值
accuracy = nb.score(x_test,y_test) # 根據(jù)x_test預(yù)測(cè)結(jié)果,把預(yù)測(cè)結(jié)果和真實(shí)的y_test比較,計(jì)算準(zhǔn)確率
# 預(yù)測(cè),輸入預(yù)測(cè)所需的特征值x(非sparss矩陣)
result = nb.predict(news_predict_data)
總結(jié)
以上是生活随笔為你收集整理的【机器学习入门】(2) 朴素贝叶斯算法:原理、实例应用(文档分类预测)附python完整代码及数据集的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【机器学习入门】(1) K近邻算法:原理
- 下一篇: 【机器学习入门】(3) 朴素贝叶斯算法: