發布時間: 2019-07-11 17:46:15
在開始介紹貝葉斯之前,先簡單介紹下概率的基礎知識。概率是某一結果出現的可能性。例如,拋一枚勻質硬幣,正面向上的可能性多大?概率值是一個0-1之間的數字,用來衡量一個事件發生可能性的大小。概率值越接近1,事件發生的可能性越大,概率值越接近0,事件越不可能發生。我們日常生活中聽到最多的是天氣預報中的降水概率。概率的表示方法叫維恩圖。下面我們通過維恩圖來說明貝葉斯公式中常見的幾個概率。
在維恩圖中:
S:S是樣本空間,是所有可能事件的總和。
?P(A):是樣本空間S中A事件發生的概率,維恩圖中綠色的部分。
?P(B):是樣本空間S中B事件發生的概率,維恩圖中藍色的部分。
?P(A∩B):是樣本空間S中A事件和B事件同時發生的概率,也就是A和B相交的區域。
?P(A|B):是條件概率,是B事件已經發生時A事件發生的概率。
貝葉斯算法通過已知的P(A|B),P(A),和P(B)三個概率計算P(B|A)發生的概率。假設我們現在已知P(A|B),P(A)和P(B)三個概率,如何計算P(B|A)呢?通過前面的概率樹及P(A|B)的概率可知,P(B|A)的概率是在事件A發生的前提下事件B發生的概率,因此P(B|A)可以表示為事件B與事件A的交集與事件A的比率。
?
在貝葉斯推斷中,每一種概率都有一個特定的名字:
?P(B)是”先驗概率”(Prior probability)。
?P(A)是”先驗概率”(Prior probability),也作標準化常量(normalized constant)。
?P(A|B)是已知B發生后A的條件概率,叫做似然函數(likelihood)。
?P(B|A)是已知A發生后B的條件概率,是我們要求的值,叫做后驗概率。
?P(A|B)/P(A)是調整因子,也被稱作標準似然度(standardised likelihood)。
?
解決問題
下面從一個簡單問題出發,介紹怎么使用樸素貝葉斯解決分類問題。
一天,老師問了個問題,只根據頭發和聲音怎么判斷一位同學的性別。
為了解決這個問題,同學們馬上簡單的統計了7位同學的相關特征,數據如下:?
頭發 | 聲音 | 性別 |
長 | 粗 | 男 |
短 | 粗 | 男 |
短 | 粗 | 男 |
長 | 細 | 女 |
短 | 細 | 女 |
短 | 粗 | 女 |
長 | 粗 | 女 |
長 | 粗 | 女 |
這個問題之前用決策樹做過了,這里我們換一種思路。
要是知道男生和女生頭發長短的概率以及聲音粗細的概率,我們就可以計算出各種情況的概率,然后比較概率大小,來判斷性別。
假設抽樣樣本足夠大,我們可以近似認為可以代表所有數據,假設上位7位同學能代表所有數據,這里方便計算~
由這7位同學,我們馬上得出下面表格概率分布。
概率分布?
性別 | 頭發長 | 聲音粗 |
男 | 1/3 | 1 |
女 | 3/5 | 3/5 |
公式中,事件Bi的概率為P(Bi),事件Bi已發生條件下事件A的概率為P(A│Bi),事件A發生條件下事件Bi的概率為P(Bi│A)。
帶入我們的例子中,判斷頭發長的人性別:
P(男|頭發長)=P(頭發長|男)*P(男)/P(頭發長)
P(女|頭發長)=P(頭發長|女)*P(女)/P(頭發長)
判斷頭發長、聲音粗的人性別:
P(男|頭發長聲音粗)=P(頭發長|男)P(聲音粗|男)*P(男)/P(頭發長聲音粗)
P(女|頭發長聲音粗)=P(頭發長|女)P(聲音粗|女)*P(女)/P(頭發長聲音粗)
可以看到,比較最后比較概率,只用比較分子即可。也就是前面計算頭發長聲音粗的人是男生女生的概率。
?
樸素貝葉斯分類的工作流程?
樸素貝葉斯python實例?
實例內容?
假設有兩類數據p1(x,y)表示(x,y)屬于類別1,用p2(x,y)表示(x,y)屬于類別2,那么對于一個新的數據集(x,y),可以根據一下規則來判斷他的類別
1.如果p1(x,y)>p2(x,y),則(x,y)屬于類別1
2.如果p2(x,y)>p1(x,y),則(x,y)屬于類別2
也就是說,我們會選擇具有最高概率的決策,這就是貝葉斯決策理論的核心思想通常,事件A在事件B(發生)的條件下的概率,與事件B在事件A的條件下的概率是不一樣的;然而,這兩者是有確定的關系,貝葉斯法則就是這種關系的陳述。作為一個規范的原理,貝葉斯法則對于所有概率的解釋是有效的;然而,頻率主義者和貝葉斯主義者對于在應用中概率如何被賦值有著不同的看法:頻率主義者根據隨機事件發生的頻率,或者總體樣本里面的個數來賦值概率;貝葉斯主義者要根據未知的命題來賦值概率。一個結果就是,貝葉斯主義者有更多的機會使用貝葉斯法則。
14個里面有5個不買電腦,9個買電腦。
p(age=youth|buy_computer=yes) = 2/9 =0.222
p(age=youth|buy_computer=no) = 3/5 = 0.6
p(student=yes|buy_computer=yes) = 6/9 =0.667
p(student=yes|buy_computer=no) = 1/5 = 0.2
p(age=senior & student=yes|buy_computer=yes) = 2/3 =0.667
p(age=senior & student=yes|buy_computer=no) = 1/3 = 0.333
Python代碼
class NBClassify(object):
def __init__(self, fillNa = 1):
self.fillNa = 1 pass
def train(self, trainSet):
# 計算每種類別的概率 # 保存所有tag的所有種類,及它們出現的頻次 dictTag = {}
for subTuple in trainSet: dictTag[str(subTuple[1])] = 1 if str(subTuple[1]) not in dictTag.keys() else dictTag[str(subTuple[1])] + 1
# 保存每個tag本身的概率 tagProbablity = {}
totalFreq = sum([value for value in dictTag.values()])
for key, value in dictTag.items(): tagProbablity[key] = value / totalFreq # print(tagProbablity)
self.tagProbablity = tagProbablity ##############################################################################
# 計算特征的條件概率 # 保存特征屬性基本信息{特征1:{值1:出現5次, 值2:出現1次}, 特征2:{值1:出現1次, 值2:出現5次}} dictFeaturesBase = {}
for subTuple in trainSet: for key, value in subTuple[0].items(): if key not in dictFeaturesBase.keys(): dictFeaturesBase[key] = {value:1} else: if value not in dictFeaturesBase[key].keys(): dictFeaturesBase[key][value] = 1 else: dictFeaturesBase[key][value] += 1 # dictFeaturesBase = { # '職業': {'農夫': 1, '教師': 2, '建筑工人': 2, '護士': 1}, # '癥狀': {'打噴嚏': 3, '頭痛': 3} # }
dictFeatures = {}.fromkeys([key for key in dictTag])
for key in dictFeatures.keys():
dictFeatures[key] = {}.fromkeys([key for key in dictFeaturesBase])
for key, value in dictFeatures.items():
for subkey in value.keys(): value[subkey] = {}.fromkeys([x for x in dictFeaturesBase[subkey].keys()])
# dictFeatures = { # '感冒 ': {'癥狀': {'打噴嚏': None, '頭痛': None}, '職業': {'護士': None, '農夫': None, '建筑工人': None, '教師': None}}, # '腦震蕩': {'癥狀': {'打噴嚏': None, '頭痛': None}, '職業': {'護士': None, '農夫': None, '建筑工人': None, '教師': None}}, # '過敏 ': {'癥狀': {'打噴嚏': None, '頭痛': None}, '職業': {'護士': None, '農夫': None, '建筑工人': None, '教師': None}} # }
# initialise dictFeatures for subTuple in trainSet:
for key, value in subTuple[0].items(): dictFeatures[subTuple[1]][key][value] = 1 if dictFeatures[subTuple[1]][key][value] == None else dictFeatures[subTuple[1]][key][value] + 1
# print(dictFeatures) # 將馴良樣本中沒有的項目,由None改為一個非常小的數值,表示其概率極小而并非是零 for tag, featuresDict in dictFeatures.items(): for featureName, fetureValueDict in featuresDict.items(): for featureKey, featureValues in fetureValueDict.items(): if featureValues == None: fetureValueDict[featureKey] = 1
# 由特征頻率計算特征的條件概率P(feature|tag) for tag, featuresDict in dictFeatures.items():
for featureName, fetureValueDict in featuresDict.items():
totalCount = sum([x for x in fetureValueDict.values() if x != None])
for featureKey, featureValues in fetureValueDict.items(): fetureValueDict[featureKey] = featureValues/totalCount if featureValues != None else None
self.featuresProbablity = dictFeatures ##############################################################################
def classify(self, featureDict):
resultDict = {}
# 計算每個tag的條件概率 for key, value in self.tagProbablity.items():
iNumList = [] for f, v in featureDict.items(): if self.featuresProbablity[key][f][v]: iNumList.append(self.featuresProbablity[key][f][v])
conditionPr = 1
for iNum in iNumList: conditionPr *= iNum
resultDict[key] = value * conditionPr
# 對比每個tag的條件概率的大小 resultList = sorted(resultDict.items(), key=lambda x:x[1], reverse=True) return resultList[0][0]
if __name__ == '__main__':
trainSet = [ ({"癥狀":"打噴嚏", "職業":"護士"}, "感冒 "), ({"癥狀":"打噴嚏", "職業":"農夫"}, "過敏 "), ({"癥狀":"頭痛", "職業":"建筑工人"}, "腦震蕩"), ({"癥狀":"頭痛", "職業":"建筑工人"}, "感冒 "), ({"癥狀":"打噴嚏", "職業":"教師"}, "感冒 "), ({"癥狀":"頭痛", "職業":"教師"}, "腦震蕩"), ]
trainSet = [ ({"age":"youth", "收入":"高","學生":"no","信用":"fair"}, "不買"), ({"age":"youth", "收入":"高","學生":"no","信用":"excellent"}, "不買"), ({"age":"midden_aged", "收入":"高","學生":"no","信用":"fair"}, "買"), ({"age":"senior", "收入":"中等","學生":"no","信用":"fair"}, "買"), ({"age":"senior", "收入":"低","學生":"yes","信用":"fair"}, "買"),
({"age":"senior", "收入":"低","學生":"yes","信用":"excellent"}, "不買"), ({"age":"midden_aged", "收入":"低","學生":"yes","信用":"excellent"}, "買"), ({"age":"youth", "收入":"中等","學生":"no","信用":"fair"}, "不買"), ({"age":"youth", "收入":"低","學生":"yes","信用":"fair"}, "買"), ({"age":"senior", "收入":"中等","學生":"yes","信用":"fair"}, "買"),
({"age":"youth", "收入":"中等","學生":"yes","信用":"excellent"}, "買"), ({"age":"midden_aged", "收入":"中等","學生":"no","信用":"excellent"}, "買"), ({"age":"midden_aged", "收入":"高","學生":"yes","信用":"fair"}, "買"), ({"age":"senior", "收入":"中等","學生":"no","信用":"excellent"}, "不買") ]
monitor = NBClassify()
# trainSet is something like that [(featureDict, tag), ] monitor.train(trainSet)
# 打噴嚏的建筑工人 # 請問他患上感冒的概率有多大? # result = monitor.classify({"癥狀":"頭痛", "職業":"教師"})
result = monitor.classify({"age":"midden_aged", "收入":"高","學生":"yes","信用":"excellent"}) print(result)
|
?樸素貝葉斯優缺點
優點:在數據較少的請胯下仍然有效,可以處理多類別問題;
缺點:對于輸入數據的準備方式較為敏感。
使用數據類型:標稱型數據