機器學習入門之樸素貝葉斯法
樸素貝葉斯法
樸素貝葉斯法是基於貝葉斯定理和特徵條件獨立假設分類方法。對於給定訓練集,首先基於特徵條件獨立性的假設,學習輸入/輸出聯合概率(計算出先驗概率和條件概率,然後求出聯合概率)。然後基於此模型,給定輸入x,利用貝葉斯概率定理求出最大的後驗概率作為輸出y。樸素貝葉斯法實現簡單,學習和預測效率都很高,是一種常用的分類方法。
1、樸素貝葉斯法的學習與分類
1.1、基本方法
設輸入空間X∈Rn為n維向量的集合,輸出空間為類標記集合Y={c_1,c_2,⋯c_K},輸入特徵向量x∈X,輸出為類標記y∈Y,X是定義為輸入空間的隨機變數,Y是輸出空間的隨機變數,P(X,Y)是聯合概率分佈,訓練資料集:
由獨立同分布產生。
樸素貝葉斯法是通過訓練集學習聯合概率分佈P(X,Y),具體的則是學習先驗概率分佈和條件概率分佈。
先驗概率分佈:
條件概率分佈:
於是學習到聯合概率P(X,Y)。
樸素貝葉斯法對條件概率分佈進行了獨立性條件假設。即:
條件獨立性的假設等於說用於分類的特徵在類確定的條件下都是獨立條件,這一假設使得樸素貝葉斯法變得簡單,但有時會犧牲一定的分類準確率。
樸素貝葉斯法進行分類時,對給定輸入x,通過學習到的模型計算後驗概率P( Y=c_k | X=x),將後驗概率最大的類作為x的類輸出。後驗概率根據貝葉斯定理進行計算:
這是樸素貝葉斯分類器的基本公式,樸素貝葉斯分類器可以表示為:
後面的推斷是由於所有的c_k都是相同的,分母是確定的一個定值,因此只需要分子最大化。
1.2、後驗概率最大的含義
樸素貝葉斯法是將例項分到後驗概率最大類中,這等於期望風險最小化,假設選擇0-1損失函式。
其中f(x)是決策分類函式。期望風險函式為:
為了是期望風險最小:
這樣一來就可以知道期望風險最小化準則就是後驗概率最大化準則。
2、樸素貝葉斯法的引數估計
2.1、極大似然估計
在樸素貝葉斯法,學習意味著估計先驗概率P(Y=c_k )和條件概率P(X=x| Y=c_k )。也可以用極大似然估計法估計相應的概率,先驗概率P(Y=c_k )的極大似然估計是:
設第j個特徵x^j可能的取值的{a_j1,a_j1,⋯,a_(jS_j )}。條件概率的極大似然估計為:
其中x_i^j表示第i個樣本第j個特徵。a_jl是表示第j個特徵取第l的值。I為指示函式。
2.2、學習與分類演算法
2.3、貝葉斯估計
用極大似然估計可能會出現所要估計概率值為0的情況;這會影響到後驗概率的計算。使分類產生偏差,解決這一個問題的辦法是使用貝葉斯估計。具體是在條件概率的分子分母分加上一個數。如下:
其中λ≥0。等價於在隨機變數各個取值的頻數上賦予一個正數λ>0;λ=0是極大似然估計。常取λ=1,稱為拉普拉斯平滑。顯然對於任何l=1,2,⋯,S_j;k=1,2,⋯,K有:
同樣先驗概率有:
最後附上程式碼:
from math import log, exp
class Laplace(object):
def __init__(self):
self.d = {}
self.total = 0.0
self.none = 1
def exists(self, key):
return key in self.d
def getsum(self):
return self.total
def get(self, key):
if not self.exists(key):
return False, self.none
return True, self.d[key]
def getprob(self, key):
return float(self.get(key)[1]) / self.total
def samples(self):
return self.d.keys()
def add(self, key, value):
self.total += value
if not self.exists(key):
self.d[key] = 1
self.total += 1
self.d[key] += value
class Bayes(object):
def __init__(self):
# [label, Probability] map
self.d = {}
self.total = 0
# train data set
def train(self, data):
for d in data:
c = d[1] # Probability
if c not in self.d:
self.d[c] = Laplace() # Laplacian smoothing
for w in d[0]: # label
self.d[c].add(w, 1)
self.total = sum(map(lambda x: self.d[x].getsum(), self.d.keys()))
def classify(self, x):
temp = {}
for c in self.d:
temp[c] = log(self.d[c].getsum()) - log(self.total)
for w in x:
temp[c] += log(self.d[c].getprob(w))
ret, prob = 0, 0
for c in self.d:
now = 0
try:
for otherc in self.d:
now += exp(temp[otherc] - temp[c])
now = 1 / now
except OverflowError:
now = 0
if now > prob:
ret, prob = c, now
return (ret, prob)