樸素貝葉斯python程式碼實現(西瓜書)
阿新 • • 發佈:2019-08-23
樸素貝葉斯python程式碼實現(西瓜書)
摘要:
樸素貝葉斯也是機器學習中一種非常常見的分類方法,對於二分類問題,並且資料集特徵為離散型屬性的時候,
使用起來非常的方便。原理簡單,訓練效率高,擬合效果好。
樸素貝葉斯
貝葉斯公式:
樸素貝葉斯之所以稱這為樸素,是因為假設了各個特徵是相互獨立的,因此假定下公式成立:
則樸素貝葉斯演算法的計算公式如下:
在實際計算中,上面的公式會做如下略微改動:
- 由於某些特徵屬性的值P(Xi|Ci)可能很小,多個特徵的p值連乘後可能被約等於0。可以公式兩邊取log然後變乘法為加法,避免類乘問題。
- P(Ci) 和P(Xi|Ci) 一般不直接使用樣本的頻率計算出來,一般會使用拉普拉斯平滑。
上面公式中,Dc為該類別的頻數,N表示所有類別的可能數。
上面公式中,Dc,xi為該特徵對應屬性的頻數,Dc為該類別的頻數,Ni表示該特徵的可能的屬性數。
對應的西瓜書資料集為
色澤 根蒂 敲聲 紋理 臍部 觸感 好瓜 青綠 蜷縮 濁響 清晰 凹陷 硬滑 是 烏黑 蜷縮 沉悶 清晰 凹陷 硬滑 是 烏黑 蜷縮 濁響 清晰 凹陷 硬滑 是 青綠 蜷縮 沉悶 清晰 凹陷 硬滑 是 淺白 蜷縮 濁響 清晰 凹陷 硬滑 是 青綠 稍蜷 濁響 清晰 稍凹 軟粘 是 烏黑 稍蜷 濁響 稍糊 稍凹 軟粘 是 烏黑 稍蜷 濁響 清晰 稍凹 硬滑 是 烏黑 稍蜷 沉悶 稍糊 稍凹 硬滑 否 青綠 硬挺 清脆 清晰 平坦 軟粘 否 淺白 硬挺 清脆 模糊 平坦 硬滑 否 淺白 蜷縮 濁響 模糊 平坦 軟粘 否 青綠 稍蜷 濁響 稍糊 凹陷 硬滑 否 淺白 稍蜷 沉悶 稍糊 凹陷 硬滑 否 烏黑 稍蜷 濁響 清晰 稍凹 軟粘 否 淺白 蜷縮 濁響 模糊 平坦 硬滑 否 青綠 蜷縮 沉悶 稍糊 稍凹 硬滑 否
python實現
#encoding:utf-8 import pandas as pd import numpy as np class NaiveBayes: def __init__(self): self.model = {}#key 為類別名 val 為字典PClass表示該類的該類,PFeature:{}對應對於各個特徵的概率 def calEntropy(self, y): # 計算熵 valRate = y.value_counts().apply(lambda x : x / y.size) # 頻次彙總 得到各個特徵對應的概率 valEntropy = np.inner(valRate, np.log2(valRate)) * -1 return valEntropy def fit(self, xTrain, yTrain = pd.Series()): if not yTrain.empty:#如果不傳,自動選擇最後一列作為分類標籤 xTrain = pd.concat([xTrain, yTrain], axis=1) self.model = self.buildNaiveBayes(xTrain) return self.model def buildNaiveBayes(self, xTrain): yTrain = xTrain.iloc[:,-1] yTrainCounts = yTrain.value_counts()# 頻次彙總 得到各個特徵對應的概率 yTrainCounts = yTrainCounts.apply(lambda x : (x + 1) / (yTrain.size + yTrainCounts.size)) #使用了拉普拉斯平滑 retModel = {} for nameClass, val in yTrainCounts.items(): retModel[nameClass] = {'PClass': val, 'PFeature':{}} propNamesAll = xTrain.columns[:-1] allPropByFeature = {} for nameFeature in propNamesAll: allPropByFeature[nameFeature] = list(xTrain[nameFeature].value_counts().index) #print(allPropByFeature) for nameClass, group in xTrain.groupby(xTrain.columns[-1]): for nameFeature in propNamesAll: eachClassPFeature = {} propDatas = group[nameFeature] propClassSummary = propDatas.value_counts()# 頻次彙總 得到各個特徵對應的概率 for propName in allPropByFeature[nameFeature]: if not propClassSummary.get(propName): propClassSummary[propName] = 0#如果有屬性滅有,那麼自動補0 Ni = len(allPropByFeature[nameFeature]) propClassSummary = propClassSummary.apply(lambda x : (x + 1) / (propDatas.size + Ni))#使用了拉普拉斯平滑 for nameFeatureProp, valP in propClassSummary.items(): eachClassPFeature[nameFeatureProp] = valP retModel[nameClass]['PFeature'][nameFeature] = eachClassPFeature return retModel def predictBySeries(self, data): curMaxRate = None curClassSelect = None for nameClass, infoModel in self.model.items(): rate = 0 rate += np.log(infoModel['PClass']) PFeature = infoModel['PFeature'] for nameFeature, val in data.items(): propsRate = PFeature.get(nameFeature) if not propsRate: continue rate += np.log(propsRate.get(val, 0))#使用log加法避免很小的小數連續乘,接近零 #print(nameFeature, val, propsRate.get(val, 0)) #print(nameClass, rate) if curMaxRate == None or rate > curMaxRate: curMaxRate = rate curClassSelect = nameClass return curClassSelect def predict(self, data): if isinstance(data, pd.Series): return self.predictBySeries(data) return data.apply(lambda d: self.predictBySeries(d), axis=1) dataTrain = pd.read_csv("xiguadata.csv", encoding = "gbk") naiveBayes = NaiveBayes() treeData = naiveBayes.fit(dataTrain) import json print(json.dumps(treeData, ensure_ascii=False)) pd = pd.DataFrame({'預測值':naiveBayes.predict(dataTrain), '正取值':dataTrain.iloc[:,-1]}) print(pd) print('正確率:%f%%'%(pd[pd['預測值'] == pd['正取值']].shape[0] * 100.0 / pd.shape[0]))
輸出
{"否": {"PClass": 0.5263157894736842, "PFeature": {"色澤": {"淺白": 0.4166666666666667, "青綠": 0.3333333333333333, "烏 黑": 0.25}, "根蒂": {"稍蜷": 0.4166666666666667, "蜷縮": 0.3333333333333333, "硬挺": 0.25}, "敲聲": {"濁響": 0.4166666666666667, "沉悶": 0.3333333333333333, "清脆": 0.25}, "紋理": {"稍糊": 0.4166666666666667, "模糊": 0.3333333333333333, "清晰": 0.25}, "臍部": {"平坦": 0.4166666666666667, "稍凹": 0.3333333333333333, "凹陷": 0.25}, "觸感": {"硬滑": 0.6363636363636364, "軟粘": 0.36363636363636365}}}, "是": {"PClass": 0.47368421052631576, "PFeature": {"色澤": {"烏黑": 0.45454545454545453, "青綠": 0.36363636363636365, "淺白": 0.18181818181818182}, "根蒂": {"蜷縮": 0.5454545454545454, "稍蜷": 0.36363636363636365, "硬挺": 0.09090909090909091}, "敲聲": {"濁響": 0.6363636363636364, "沉悶": 0.2727272727272727, "清脆": 0.09090909090909091}, "紋理": {"清晰": 0.7272727272727273, "稍糊": 0.18181818181818182, "模糊": 0.09090909090909091}, "臍 部": {"凹陷": 0.5454545454545454, "稍凹": 0.36363636363636365, "平坦": 0.09090909090909091}, "觸感": {"硬滑": 0.7, "軟粘": 0.3}}}}
預測值 正取值
0 是 是
1 是 是
2 是 是
3 是 是
4 是 是
5 是 是
6 否 是
7 是 是
8 否 否
9 否 否
10 否 否
11 否 否
12 是 否
13 否 否
14 是 否
15 否 否
16 否 否
正確率:82.352941%
總結:
- 貝葉斯分類器是一種生成式模型,不是直接擬合分類結果,而是擬合出後驗概率公式計算對應分類的概率。
- 本文只介紹了二分類,也可以用來處理多分類問題。
- 對於小規模資料集,表現良好。
- 建立在特徵相互獨立的假設上。
- 這是我的github主頁https://github.com/fanchy,有些有意思的分享。