实验三:朴素贝叶斯算法实验
【实验目的】
理解朴素贝叶斯算法原理,掌握朴素贝叶斯算法框架。
【实验内容】
针对下表中的数据,编写python程序实现朴素贝叶斯算法(不使用sklearn包),对输入数据进行预测;
熟悉sklearn库中的朴素贝叶斯算法,使用sklearn包编写朴素贝叶斯算法程序,对输入数据进行预测;
【实验报告要求】
对照实验内容,撰写实验过程、算法及测试结果;
代码规范化:命名规则、注释;
查阅文献,讨论朴素贝叶斯算法的应用场景。
色泽 | 根蒂 | 敲声 | 纹理 | 脐部 | 触感 | 好瓜 |
青绿 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 碍滑 | 是 |
乌黑 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 碍滑 | 是 |
乌黑 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 碍滑 | 是 |
青绿 | 蜷缩 | 沉闷 | 清晰 | 凹陷 | 碍滑 | 是 |
浅白 | 蜷缩 | 浊响 | 清晰 | 凹陷 | 碍滑 | 是 |
青绿 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 是 |
乌黑 | 稍蜷 | 浊响 | 稍糊 | 稍凹 | 软粘 | 是 |
乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 硬滑 | 是 |
乌黑 | 稍蜷 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 |
青绿 | 硬挺 | 清脆 | 清晰 | 平坦 | 软粘 | 否 |
浅白 | 硬挺 | 清脆 | 模糊 | 平坦 | 硬滑 | 否 |
浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 软粘 | 否 |
青绿 | 稍蜷 | 浊响 | 稍糊 | 凹陷 | 硬滑 | 否 |
浅白 | 稍蜷 | 沉闷 | 稍糊 | 凹陷 | 硬滑 | 否 |
乌黑 | 稍蜷 | 浊响 | 清晰 | 稍凹 | 软粘 | 否 |
浅白 | 蜷缩 | 浊响 | 模糊 | 平坦 | 硬滑 | 否 |
青绿 | 蜷缩 | 沉闷 | 稍糊 | 稍凹 | 硬滑 | 否 |
实现前提
条件概率公式,是指在事件B发生的情况下,事件A发生的概率,用来表示。
概率为:
数据:
1 import numpy as np 2 import pandas as pd 3 data_list = [ 4 ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '碍滑', 'YES'], 5 ['乌黑', '蜷缩', '沉闷', '清晰', '凹陷', '碍滑', 'YES'], 6 ['乌黑', '蜷缩', '浊响', '清晰', '凹陷', '碍滑', 'YES'], 7 ['青绿', '蜷缩', '沉闷', '清晰', '凹陷', '碍滑', 'YES'], 8 ['浅白', '蜷缩', '浊响', '清晰', '凹陷', '碍滑', 'YES'], 9 ['青绿', '稍缩', '浊响', '清晰', '稍凹', '软粘', 'YES'], 10 ['乌黑', '稍缩', '浊响', '清晰', '稍凹', '软粘', 'YES'], 11 ['乌黑', '稍缩', '浊响', '清晰', '稍凹', '硬滑', 'YES'], 12 ['乌黑', '稍缩', '沉闷', '稍糊', '稍凹', '硬滑', 'NO'], 13 ['青绿', '硬挺', '清脆', '清晰', '平坦', '软粘', 'NO'], 14 ['浅白', '硬挺', '清脆', '模糊', '平坦', '硬滑', 'NO'], 15 ['浅白', '蜷缩', '浊响', '模糊', '平坦', '软粘', 'NO'], 16 ['青绿', '稍缩', '浊响', '稍糊', '凹陷', '硬滑', 'NO'], 17 ['浅白', '稍缩', '沉闷', '稍糊', '凹陷', '硬滑', 'NO'], 18 ['乌黑', '稍缩', '浊响', '清晰', '稍凹', '软粘', 'NO'], 19 ['浅白', '蜷缩', '浊响', '模糊', '稍凹', '硬滑', 'NO'], 20 ['青绿', '蜷缩', '沉闷', '稍糊', '稍凹', '硬滑', 'NO'] 21 ] 22 23 classes_list = ['色泽','根蒂','敲声','纹理','脐部','触感','好瓜'] 24 property_list = [ 25 '青绿','乌黑','浅白', 26 '蜷缩','稍蜷','硬挺', 27 '浊响','沉闷','清脆', 28 '清晰','稍糊','模糊', 29 '凹陷','平坦','稍凹', 30 '硬滑','软粘',]
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)) #使用了拉普拉斯平滑 分别计算YES和NO的概率 # print("1111:",yTrainCounts) # print("@@@") retModel = {} #使用拉普拉斯的模型 for nameClass, val in yTrainCounts.items(): retModel[nameClass] = {'PClass': val, 'PFeature':{}} # print("@@") # print(retModel) # print("@@") propNamesAll = xTrain.columns[:-1] #训练数据 # print("@@") # print(xTrain[propNamesAll]) # print("@@") allPropByFeature = {} for nameFeature in propNamesAll: allPropByFeature[nameFeature] = list(xTrain[nameFeature].value_counts().index)#获取每列的特征 # print("@@") # print(allPropByFeature) # print("@@") 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 # print("@@") # print(propClassSummary) # print("@@") 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 # print("@@") # print(PFeature) # print("@@") 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 = data_df 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]))
{"NO": {"PClass": 0.5263157894736842, "PFeature": {"0": {"浅白": 0.4166666666666667, "青绿": 0.3333333333333333, "乌黑": 0.25}, "1": {"稍缩": 0.4166666666666667, "蜷缩": 0.3333333333333333, "硬挺": 0.25}, "2": {"浊响": 0.4166666666666667, "沉闷": 0.3333333333333333, "清脆": 0.25}, "3": {"稍糊": 0.4166666666666667, "模糊": 0.3333333333333333, "清晰": 0.25}, "4": {"稍凹": 0.4166666666666667, "平坦": 0.3333333333333333, "凹陷": 0.25}, "5": {"硬滑": 0.5833333333333334, "软粘": 0.3333333333333333, "碍滑": 0.08333333333333333}}}, "YES": {"PClass": 0.47368421052631576, "PFeature": {"0": {"乌黑": 0.45454545454545453, "青绿": 0.36363636363636365, "浅白": 0.18181818181818182}, "1": {"蜷缩": 0.5454545454545454, "稍缩": 0.36363636363636365, "硬挺": 0.09090909090909091}, "2": {"浊响": 0.6363636363636364, "沉闷": 0.2727272727272727, "清脆": 0.09090909090909091}, "3": {"清晰": 0.8181818181818182, "稍糊": 0.09090909090909091, "模糊": 0.09090909090909091}, "4": {"凹陷": 0.5454545454545454, "稍凹": 0.36363636363636365, "平坦": 0.09090909090909091}, "5": {"碍滑": 0.5454545454545454, "软粘": 0.2727272727272727, "硬滑": 0.18181818181818182}}}} 预测值 正取值 0 YES YES 1 YES YES 2 YES YES 3 YES YES 4 YES YES 5 YES YES 6 YES YES 7 YES YES 8 NO NO 9 NO NO 10 NO NO 11 NO NO 12 NO NO 13 NO NO 14 YES NO 15 NO NO 16 NO NO 正确率:94.117647%
sklearn包中的朴素贝叶斯
1 from sklearn.model_selection import train_test_split 2 import numpy as np 3 data_list = [#青绿 0 乌黑 1 浅白 2 蜷缩 0 稍缩 1 硬挺 2 浊响 0 沉闷 1 清脆 2 清晰 0 稍糊 1 模糊 2 平坦 0 稍凹 1 凹陷 2 碍滑 0 软粘 1 硬滑 2 4 [0, 0, 0, 0, 2, 0, 1], 5 [1, 0, 1, 0, 2, 0, 1], 6 [1, 0, 0, 0, 2, 0, 1], 7 [0, 0, 1, 0, 2, 0, 1], 8 [2, 0, 0, 0, 2, 0, 1], 9 [0, 1, 0, 0, 1, 1, 1], 10 [1, 1, 0, 0, 1, 1, 1], 11 [1, 1, 0, 0, 1, 2, 1], 12 [1, 1, 1, 1, 1, 2, 0], 13 [0, 2, 2, 0, 0, 1, 0], 14 [2, 2, 2, 2, 0, 2, 0], 15 [2, 0, 0, 2, 0, 1, 0], 16 [0, 1, 0, 1, 2, 2, 0], 17 [2, 1, 1, 1, 2, 2, 0], 18 [1, 1, 0, 0, 1, 1, 0], 19 [2, 0, 0, 2, 1, 2, 0], 20 [0, 0, 1, 1, 1, 2, 0] 21 ] 22 target = np.array([0,1,2,3,4,5,6],dtype='float32') 23 data = np.array(data_list,dtype='float32')
1 from sklearn.naive_bayes import GaussianNB 2 from sklearn.model_selection import train_test_split 3 x_train,x_test,y_train,y_test = train_test_split(data.T,target,random_state=1) #按比例分割数据 4 nb_clf = GaussianNB() #实例化模型 5 nb_clf.fit(x_train,y_train) #模型训练 6 a=nb_clf.predict(x_test) #预测 7 acc_score = nb_clf.score(x_test,y_test) #查看模型分数
预测结果: