监督学习 | 朴素贝叶斯原理及Python实现
文章目錄
- 1. 貝葉斯理論
- 1.1 貝葉斯定理
- 1.2 貝葉斯分類算法
- 1.3 樸素貝葉斯分類算法
- 1.3.1 樸素貝葉斯分類器實例
- 學習過程
- 預測過程
- 2. Python實現
- 2.1 拉普拉斯修正
- 2.2 對數變換
- 參考資料
相關文章:
機器學習 | 目錄
監督學習 | 樸素貝葉斯Sklearn實現
1. 貝葉斯理論
1.1 貝葉斯定理
貝葉斯定理旨在計算P(A∣B)P(A|B)P(A∣B)的值,也就是在已知B發生的條件下,A發生的概率是多少。大多數情況下,B是被觀察事件,比如“昨天下雨了”,A為預測結果“今天會下雨”。[1]
對數據挖掘來說,B通常通常是樣本個數,A為被預測個體所屬類別
貝葉斯定理公式入下:
P(A∣B)=P(B∣A)P(A)P(B)(1)P(A|B)=\frac{P(B|A)P(A)}{P(B)} \tag{1} P(A∣B)=P(B)P(B∣A)P(A)?(1)
舉例說明:我們想計算含有單詞money的郵件為垃圾郵件的概率。
-
P(A):在這里,A為“這是封垃圾郵件”。我們可以通過統計訓練集中垃圾郵件的比例,得到先驗概率(prior probability):P(A)P(A)P(A),如果我們的數據集每100封郵件有30封垃圾郵件,則P(A)=0.3P(A)=0.3P(A)=0.3。
-
P(B):B表示“該郵件含有單詞money”。類似地,我們通過計算數據集中含有單詞money的郵件比例得到P(B)P(B)P(B)。如果每100封郵件中有10封郵件包含單詞money,則P(B)=0.1P(B)=0.1P(B)=0.1。計算P(B)P(B)P(B)時,我們不關注郵件是不是垃圾郵件。
-
P(B|A):指的是垃圾郵件中含有單詞money的概率,通過統計訓練集中所有垃圾郵件的數量以及其中含有單詞money的數量。30封垃圾郵件中,如果有6封含有單詞money,那么P(B∣A)=0.2P(B|A)=0.2P(B∣A)=0.2。
-
P(A|B):因此可計算P(A∣B)=P(B∣A)P(A)P(B)=0.2×0.30.1=0.6P(A|B)=\frac{P(B|A)P(A)}{P(B)}=\frac{0.2\times 0.3}{0.1}=0.6P(A∣B)=P(B)P(B∣A)P(A)?=0.10.2×0.3?=0.6,即含有單詞money的郵件為垃圾郵件的概率為60%。
1.2 貝葉斯分類算法
貝葉斯分類算法,就是利用貝葉斯定理對數據進行分類。
其基本表達式為:
其中:
P(X=x∣Y=ck)P(Y=ck)=P(x(1),x(2),...,x(m)∣Y=ck),k=1,2,...,n(4)P(X=x|Y=c_k)P(Y=c_k)=P(x^{(1)}, x^{(2)},..., x^{(m)}|Y=c_k), k=1,2,...,n \tag{4}P(X=x∣Y=ck?)P(Y=ck?)=P(x(1),x(2),...,x(m)∣Y=ck?),k=1,2,...,n(4)
1.3 樸素貝葉斯分類算法
對于貝葉斯算法,其適用于只用一個特征的分類。當有多個特征時,由于特征之間不獨立,因此P(X=x∣Y=ck)P(X=x|Y=c_k)P(X=x∣Y=ck?)的計算非常復雜,假設xxx的第jjj特征x(j)x^{(j)}x(j)可取的值有SjS_jSj?個,YYY可取的值有nnn個,那么要計算的參數個數為n×∏j=1mSjn\times \prod_{j=1}^mS_jn×∏j=1m?Sj?,對這樣指數量級的參數進行估計是不實際的,所有有了樸素貝葉斯中的獨立性假設。[2]
樸素貝葉斯算法在貝葉斯算法的基礎上,多了兩個默認的前提條件:
由獨立性假設:
在獨立性假設下,將原本指數級的n×∏j=1mSjn\times \prod_{j=1}^mS_jn×∏j=1m?Sj?個變為常數級的nSjnS_jnSj?個。
由此有:
注意到,分母對于所有ckc_kck?都是相同的。
因此得到樸素貝葉斯算法的基本表達式:
1.3.1 樸素貝葉斯分類器實例
預測某人是否拖欠貸款(Y:c1=yes,c2=noY: {c_1=yes,c_2=no}Y:c1?=yes,c2?=no)
| 是 | 125k | no |
| 否 | 100k | no |
| 否 | 70k | no |
| 是 | 120k | no |
| 否 | 95k | yes |
| 否 | 60k | no |
| 是 | 220k | no |
| 否 | 85k | yes |
| 否 | 75k | no |
| 否 | 90k | yes |
學習過程
-
計算先驗分布:
P(Y=yes)=310P(Y=yes)= \frac{3}{10}P(Y=yes)=103?,P(Y=no)=710P(Y=no)= \frac{7}{10}P(Y=no)=107?
-
對于x(1)x^{(1)}x(1)有房,計算條件分布:
P(有房=是∣Y=yes)=0P(有房 = 是 |Y=yes)= 0P(有房=是∣Y=yes)=0,P(有房=是∣Y=no)=37P(有房=是|Y=no)= \frac{3}{7}P(有房=是∣Y=no)=73?
P(有房=否∣Y=yes)=1P(有房 = 否 |Y=yes)= 1P(有房=否∣Y=yes)=1,P(有房=否∣Y=no)=47P(有房=否|Y=no)= \frac{4}{7}P(有房=否∣Y=no)=74?
-
對于x(2)x^{(2)}x(2)收入,計算條件分布:
年收入可視為連續值,在此先離散化,后計算概率:
(低:年收入≤90k,中:年收入≤150k,高:年收入≥150k{低:年收入 \leq 90k,中:年收入 \leq 150k,高:年收入 \ge 150k}低:年收入≤90k,中:年收入≤150k,高:年收入≥150k)P(年收入=高∣Y=yes)=0P(年收入 = 高 |Y=yes)= 0P(年收入=高∣Y=yes)=0,P(年收入=高∣Y=no)=17P(年收入 = 高|Y=no)= \frac{1}{7}P(年收入=高∣Y=no)=71?
P(年收入=中∣Y=yes)=13P(年收入 = 中 |Y=yes)= \frac{1}{3}P(年收入=中∣Y=yes)=31?,P(年收入=中∣Y=no)=37P(年收入 = 中|Y=no)= \frac{3}{7}P(年收入=中∣Y=no)=73?
P(年收入=低∣Y=yes)=12P(年收入 = 低 |Y=yes)= \frac{1}{2}P(年收入=低∣Y=yes)=21?,P(年收入=低∣Y=no)=37P(年收入 = 低|Y=no)= \frac{3}{7}P(年收入=低∣Y=no)=73?
預測過程
假設預測樣本x?=有房=否,年收入=110kx_*={有房=否,年收入=110k}x??=有房=否,年收入=110k,預測x?x_*x??是否有可能拖欠貸款
根據模型表達式:y=argmax?ckP(Y=ck)∏j=1mP(X(j)=x(j)∣Y=ck)y = arg \max \limits_{c_k} P(Y=c_k) \prod_{j=1}^mP(X^{(j)}=x^{(j)}|Y=c_k)y=argck?max?P(Y=ck?)∏j=1m?P(X(j)=x(j)∣Y=ck?)
-
計算:
P(Y=no∣X=x?)=P(Y=no)P(有房=否∣Y=no)P(年收入=中∣Y=no)=710×47×37=1270P(Y=no|X=x_*)=P(Y=no)P(有房=否|Y=no)P(年收入=中|Y=no)= \frac{7}{10} \times \frac{4}{7} \times \frac{3}{7}= \frac{12}{70}P(Y=no∣X=x??)=P(Y=no)P(有房=否∣Y=no)P(年收入=中∣Y=no)=107?×74?×73?=7012?
P(Y=yes∣X=x?)=P(Y=yes)P(有房=否∣Y=yes)P(年收入=中∣Y=yes)=310×1×13=770P(Y=yes|X=x_*)=P(Y=yes)P(有房=否|Y=yes)P(年收入=中|Y=yes)= \frac{3}{10} \times 1 \times \frac{1}{3}= \frac{7}{70}P(Y=yes∣X=x??)=P(Y=yes)P(有房=否∣Y=yes)P(年收入=中∣Y=yes)=103?×1×31?=707?
因此y=argmax?ck{P(Y=no∣X=x?),P(Y=yes∣X=x?)}=1270y = arg \max \limits_{c_k} \{P(Y=no|X=x_*), P(Y=yes|X=x_*)\} = \frac{12}{70}y=argck?max?{P(Y=no∣X=x??),P(Y=yes∣X=x??)}=7012?
所以x?x_*x??的類別為no,即不會拖欠貸款。
-
P(Y=no∣X=x?),P(Y=yes∣X=x?)P(Y=no|X=x_*), P(Y=yes|X=x_*)P(Y=no∣X=x??),P(Y=yes∣X=x??) 和并不等于1,這是因為計算過程省略了分母P(X=x)P(X=x)P(X=x)。
歸一化后各自概率為:
P(Y=no∣X=x?)=63.16%P(Y=no|X=x_*)=63.16 \%P(Y=no∣X=x??)=63.16%
P(Y=yes∣X=x?)=36.84%P(Y=yes|X=x_*)=36.84 \%P(Y=yes∣X=x??)=36.84%
即有63.16%的概率認為x?x_*x??的類別為no,不會拖欠貸款。
2. Python實現
2.1 拉普拉斯修正
-
為什么需要修正:因為我們的樣本集有限,對于某些離散的值可能并沒有出現,這樣會導致概率的乘積為0,影響最終分類結果。
-
拉普拉斯修正法:對于一個離散的值,我們在使用的時候不是直接輸出它的概率,而是對概率值進行“平滑”處理。即默認所有特征都出現過一次,將概率該為下面的形式:
P(c)=∣Dc∣+1∣D∣+N(9)P(c)= \frac{|D_c|+1}{|D|+N} \tag{9}P(c)=∣D∣+N∣Dc?∣+1?(9)
P(xi∣c)=∣Dc,xi∣+1∣Dc∣+Ni(10)P(x_i|c)= \frac{|D_{c,x_i}|+1}{|D_c|+N_i} \tag{10}P(xi?∣c)=∣Dc?∣+Ni?∣Dc,xi??∣+1?(10)
其中NNN是全體特征的總數,DDD為這一類的總數目,這就避免了概率值為0的情況。[3]
但是也沒有特別的利用需要在計數結果上加1,可以使用一個很小的常數 μ\muμ 取代它:
P(xi∣c)=∣Dc,xi∣+μpxi∣Dc∣+μ(11)P(x_i | c)=\frac{|D_{c,x_i}|+\mu p_{x_i}}{|D_c|+\mu} \tag{11}P(xi?∣c)=∣Dc?∣+μ∣Dc,xi??∣+μpxi???(11)
其中 μ\muμ 為一個常數,大的 μ\muμ 值說明先驗值時非常重要的,而小的 μ\muμ 值說明先驗值的影響力較小;pxip_{x_i}pxi?? 為 xix_ixi? 的先驗概率。
2.2 對數變換
由于計算概率時需要對很多歌很小的概率值做乘法,所以有可能出現下溢的情況,所以我們可以對概率的乘積取自然對數,根據自然對數函數的單調性,不會改變最終的大小,同時也防止了下溢出現的問題。
import numpy as np import math # 使用詞集法進行貝葉斯分類 # 構造數據集,分類是侮辱性 or 非侮辱性 def loadDataset () :postingList=[['my', 'dog', 'has', 'flea', 'problems', 'help', 'please'],['maybe', 'not', 'take', 'him', 'to', 'dog', 'park', 'stupid'],['my', 'dalmation', 'is', 'so', 'cute', 'I', 'love', 'him'],['stop', 'posting', 'stupid', 'worthless', 'garbage'],['mr', 'licks', 'ate', 'my', 'steak', 'how', 'to', 'stop', 'him'],['quit', 'buying', 'worthless', 'dog', 'food', 'stupid']]classVec = [0,1,0,1,0,1] #1 is abusive, 0 notreturn postingList, classVec # 創建一個包涵所有詞匯的列表 , 為后面建立詞條向量使用 def createlist (dataset) :vovabset = set ([])for vec in dataset :vovabset = vovabset | set (vec)return list (vovabset) # 將詞條轉化為向量的形式 def changeword2vec (inputdata, wordlist) :returnVec = [0] * len (wordlist)for word in inputdata :if word in wordlist :returnVec[wordlist.index(word)] = 1return returnVec # 創建貝葉斯分類器 def trainNBO (dataset, classlebels) :num_of_sample = len (dataset)num_of_feature = len (dataset[0])pAusuive = sum (classlebels) / num_of_sample # 侮辱性語言的概率p0Num = np.ones (num_of_feature)p1Num = np.ones (num_of_feature)p0tot = num_of_featurep1tot = num_of_featurefor i in range (num_of_sample) :if classlebels[i] == 1 :p1Num += dataset[i]p1tot += sum (dataset[i])else :p0Num += dataset[i]p0tot += sum (dataset[i]) p0Vec = p0Num / p0totp1Vec = p1Num / p1totfor i in range (num_of_feature) :p0Vec[i] = math.log (p0Vec[i])p1Vec[i] = math.log (p1Vec[i])return p0Vec, p1Vec, pAusuive # 定義分類器 def classifyNB(vec2Classify, p0Vec, p1Vec, pClass1):p1 = sum(vec2Classify * p1Vec) + log(pClass1) #element-wise multp0 = sum(vec2Classify * p0Vec) + log(1.0 - pClass1)if p1 > p0:return 1else: return 0 # 測試代碼 dataset,classlebels = loadDataset () wordlist = createlist (dataset) print (wordlist) print (changeword2vec (dataset[0], wordlist)) trainmat = [] for temp in dataset :trainmat.append (changeword2vec (temp,wordlist)) p0V, p1V, pAb = trainNBO (trainmat, classlebels) print (p0V) print (p1V) print (pAb) ['please', 'problems', 'ate', 'is', 'flea', 'maybe', 'love', 'food', 'him', 'take', 'has', 'help', 'my', 'cute', 'stupid', 'dalmation', 'posting', 'worthless', 'steak', 'so', 'licks', 'quit', 'to', 'dog', 'not', 'how', 'park', 'garbage', 'mr', 'stop', 'buying', 'I'] [1, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0] [-3.33220451 -3.33220451 -3.33220451 -3.33220451 -3.33220451 -4.02535169-3.33220451 -4.02535169 -2.9267394 -4.02535169 -3.33220451 -3.33220451-2.63905733 -3.33220451 -4.02535169 -3.33220451 -4.02535169 -4.02535169-3.33220451 -3.33220451 -3.33220451 -4.02535169 -3.33220451 -3.33220451-4.02535169 -3.33220451 -4.02535169 -4.02535169 -3.33220451 -3.33220451-4.02535169 -3.33220451] [-3.93182563 -3.93182563 -3.93182563 -3.93182563 -3.93182563 -3.23867845-3.93182563 -3.23867845 -3.23867845 -3.23867845 -3.93182563 -3.93182563-3.93182563 -3.93182563 -2.54553127 -3.93182563 -3.23867845 -2.83321334-3.93182563 -3.93182563 -3.93182563 -3.23867845 -3.23867845 -2.83321334-3.23867845 -3.93182563 -3.23867845 -3.23867845 -3.93182563 -3.23867845-3.23867845 -3.93182563] 0.5參考資料
[1] Robert Layton,杜春曉. Python數據挖掘入門與實踐[M]. 北京: 人民郵電出版社, 2016: 93-103.
[2] GoWeiXH.機器學習 - 樸素貝葉斯(下)- 樸素貝葉斯分類器[EB/OL].https://blog.csdn.net/weixin_37352167/article/details/84867145, 2018-02-06.
[3] Glory_g.貝葉斯分類器以及Python實現[EB/OL].https://blog.csdn.net/zhelong3205/article/details/78659169, 2017-11-28.
總結
以上是生活随笔為你收集整理的监督学习 | 朴素贝叶斯原理及Python实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何用Linux的命令正确识别cpu的个
- 下一篇: Ubuntu下搭建MPI并行计算环境