朴素贝叶斯西瓜分类

Python实现朴素贝叶斯西瓜分类

实验目的

用python实现朴素贝叶斯算法西瓜分类,根据给出的特征和数据来训练一个朴素贝叶斯分类器。

实验环境

Python3.8

项目内容(作业任务、算法原理)

贝叶斯分类器的理论框架基于贝叶斯决策论(Bayesian decision theory),而贝叶斯决策论是概率框架下实施决策的基本方法。对分类任务来说,在所有相关概率都已知的理想情形下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最优的类别标记。

具体来说,若我们决策的目标是最小化分类错误率,贝叶斯最优分类器要对每个样本 x,选择能使后验概率 P( c | x )最大的类别 c 标记。可在现实任务中后验概率通常难以直接获得,贝叶斯分类器使用的策略是“生成型模型”,即使用贝叶斯定理:

P( c | x ) = P( c, x ) / P( x ) = P( c )P( x | c ) / P( x )

将求后验概率P(c|x)的问题转变为求先验概率P(c)和条件概率P(x|c)。

而本次作业任务就是用python实现贝叶斯分类器的理论,实现对西瓜的分类。

实验结果及结果分析

4.1 数据集及评估方法

数据集:西瓜的数据集.csv、西瓜的验证集.csv

评估方法:留出法

4.2 模型对比(表格、结果展示截图等)

目前常用的模型有以下几种:

(1)“判别式模型”,直接通过建模P(c|x)来预测类别c的模型就是判别式模型,主要算法:决策树、BP神经网络、支持向量机等。

(2)“生成式模型”,先对联合概率分布P(x,c)建模,然后再由此获得P(c|x)的模型就是生成式模型,主要算法:朴素贝叶斯、贝叶斯网络、马尔可夫随机场。

(3)大数定律,这是一种描述当试验次数很大时所呈现的概率性质的定律。通俗地说,这个定理就是,在试验不变的条件下,重复试验多次,随机事件的频率近似于它的概率。偶然中包含着某种必然。

(4)极大似然估计,根据数据采样来估计概率分布参数的经典方法,比如对参数 t 进行极大似然估计,就是试图在 t 所有可能的取值中,找到一个能使数据出现的“可能性”最大的值。

(5)吉布斯采样,吉布斯采样是一种随机采样方法,首先根据已知初始值 e 产生一个初始点 q0,然后进行 T 次采样,每次根据第 t-1 次的结果 q(t-1) 生成一个新的第 t 次的采样样本 qt,每次采样后与查询变量 q 进行比对,一致则计数器 n 加一。T 次采样结束后, n 除以 T 的值可作为后验概率 P( q | e ) 的近似估算。

(6)EM(Expectation-Maximization)算法,EM算法使用两个步骤交替计算:第一步是期望(E)步,利用当前估计的参数值来计算对数似然的期望值;第二步是最大化(M)步,寻找能使 E 步产生的似然期望最大化的参数值。然后,新得到的参数值重新被用于 E 步并开始下一轮的计算,直到收敛到局部最优解。

其中,经过查阅资料,决定采用生成式模型中的朴素贝叶斯进行分类。

编写python代码,读入西瓜的数据集进行运算后,利用西瓜的测试集计算模型准确率。

python代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
import numpy as np
import pandas as pd

"""
load_data_set():
功能:载入数据集
输入:无
返回:
posting_list:数据集;
classes_list:各属性的类别
property_list:各个属性的属性值集合列表
"""

def csv_input(CSV_FILE_PATH):
df = pd.read_csv(CSV_FILE_PATH)
# print(df.values.tolist())
return df.values.tolist()

def load_data_set():
posting_list=csv_input('./西瓜的数据集.csv')

# 各个属性的属性值集合列表
property_list = [
'青绿', '乌黑', '浅白',
'蜷缩', '稍缩', '硬挺',
'浊响', '沉闷', '清脆',
'清晰', '稍糊', '模糊',
'凹陷', '稍陷', '稍凹',
'硬滑', '软粘']
return posting_list, property_list


"""
getNums(posting_list,col,rows,nums):
功能:取值函数,从数据集中取出某一列(密度或者含糖率样本)多行的值,返回一维数组,及其长度
输入:posting_list:数据集;col:所取数据集的列号;rows:所取数据集的开始行号;nums:取的数据行数;
输出:Nums:浮点型数据列表
"""


def getNums(posting_list, col, rows, nums):
Nums = [0] * nums
for n in range(0, nums):
Nums[n] = float(posting_list[rows + n][col])
return Nums


"""
train_naive_bayes(posting_list,property_list):
功能:训练数据,即计算数据集的类条件概率,类先验概率
输入:posting_list:数据集;property_list:各个属性的属性值集合构成的列表
输出:propertyConditionalProbabilityPositive:正样本(好瓜)类条件概率
propertyConditionalProbabilityNegative:负样本类条件概率
"""


def train_naive_bayes(posting_list, property_list):
# 总的样本数目
trainNum = len(posting_list)
# 正样本数目
pSampleNum = 0
for sample in posting_list:
if sample[-1] == '是':
pSampleNum += 1
# 类先验概率
prioClass = pSampleNum / trainNum
# 存储正样本类条件概率
propertyConditionalProbabilityPositive = []
propertyConditionalProbabilityNegative = []

# 通过遍历各个属性的属性值集合列表来求其属于 正/负样本的类条件概率,property_list含所有的属性值(无含糖率和密度)
for propertyy in property_list:
# 拉普拉斯平滑,防止为0, 西瓜书p153
# 触感属性只有两个值:硬滑和软粘;拉普拉斯平滑时,该属性正/负样本数目即分母加2,其他属性正/负样本数目即其分母加3
if (propertyy == "硬滑") or (propertyy == "软粘"):
pSampleNumLap = pSampleNum + 2
nSampleNumLap = trainNum - pSampleNum + 2
else:
pSampleNumLap = pSampleNum + 3
nSampleNumLap = trainNum - pSampleNum + 3

# 拉普拉斯平滑,初始化为1
posNumPropertyPositive = 1
negNumPropertyPositive = 1

# 遍历数据集的每一个样本
for rows in range(0, len(posting_list)):
# 如果此时的属性值在样本中
if propertyy in posting_list[rows]:
# 如果该样本为正样本
if posting_list[rows][-1] == '是':
# 计算此属性值的正样本数目
posNumPropertyPositive += 1

else:
# 计算此属性值的负样本数目
negNumPropertyPositive += 1
# 计算此属性值的正/负类条件概率
propertyConditionalProbabilityPositive.append(posNumPropertyPositive / pSampleNumLap)
propertyConditionalProbabilityNegative.append(negNumPropertyPositive / nSampleNumLap)


return propertyConditionalProbabilityPositive, propertyConditionalProbabilityNegative


"""
classify_naive_bayes(data,propertyConditionalProbabilityPositive,property_list,propertyConditionalProbabilityNegative):
功能:求正负类别的概率,返回1或者0, 1表示为正样本
输入:data:想要测试的数据,格式见底部说明。propertyConditionalProbabilityPositive正类条件概率;propertyConditionalProbabilityNegative负类条件概率
输出:返回1或者0;其中1代表正样本(好瓜),0代表负样本
"""


def classify_naive_bayes(data, propertyConditionalProbabilityPositive, property_list,
propertyConditionalProbabilityNegative):
probabilityPos = 0
probabilityNeg = 0
# 遍历测试数据的属性, 其密度和含糖率不在循环中计算
for propertyData in data[:-1]:
if propertyData in property_list:
# 取该属性的下标
index = property_list.index(propertyData)
# 取该属性值的正/负样本类条件概率 值,并取对数,然后加起来来求正负样本各自的概率。 取对数为了防止下溢,将乘法转为加法计算。
probabilityPos += np.log(propertyConditionalProbabilityPositive[index])
probabilityNeg += np.log(propertyConditionalProbabilityNegative[index])

# 对算出来的正负概率进行比较,大的为正样本
if probabilityPos > probabilityNeg:
return 1
else:
return 0


if __name__ == "__main__":
# 载入数据
posting_list, property_list = load_data_set()
# 预训练
propertyConditionalProbabilityPositive, propertyConditionalProbabilityNegative = train_naive_bayes(posting_list,
property_list)

# 朴素贝叶斯求类别

data=[]
data=csv_input('./西瓜的测试集.csv')
accuracy=0
for n in range(0,len(data)):
result = classify_naive_bayes(data[n], propertyConditionalProbabilityPositive, property_list,
propertyConditionalProbabilityNegative)
if result==1 and data[n][-1]=='是' or result==0 and data[n][-1]=='否':
accuracy+=1
print('is it the good melon : {} {}'.format(result,data[n][-1]))
print('准确率为:{}'.format(accuracy/len(data)) )

is it  the good melon : 1  是
is it  the good melon : 0  否
is it  the good melon : 0  否
is it  the good melon : 1  是
is it  the good melon : 0  否
is it  the good melon : 0  否
is it  the good melon : 1  是
is it  the good melon : 0  否
is it  the good melon : 1  否
准确率为:0.8888888888888888

朴素贝叶斯西瓜分类
http://example.com/2022/12/31/朴素贝叶斯西瓜分类/
作者
Magnesium
发布于
2022年12月31日
许可协议