我们是否可以通过计算样例分类的概率来对样例进行分类呢,即一个样例分为正例的概率为0.9,分为反例的概率为0.5,那么我们将该样例分为正例。
那么我们的目标就是求P(正)和P(反)。
每一个样例都是由多个属性组成的,我们根据属性的取值来计算概率,这是明显的条件概率P(正|X),P(反|X)。X表示各个属性组成的属性向量(x1, x2, x3,……,xn)
若各个属性之间是独立的,即各个属性独立的对分类结果产生影响,那么P(正|X)或P(反|X)的计算式为(C表示分类标签)
在数据集中我们能够通过统计得出的是,P(x|C)即分类为C的属性取值为x的概率,要将P(x|C)转换为P(c|X),我们就要用到贝叶斯公式,这也是该分类方法名字的由来。
贝叶斯公式如下:
接下来,我们来实现一下:
数据集:
编号 色泽 根蒂 敲击 纹理 脐部 触感 好瓜
0 青绿 蜷缩 浊响 清晰 凹陷 硬滑 是
1 乌黑 蜷缩 沉闷 清晰 凹陷 硬滑 是
2 乌黑 蜷缩 浊响 清晰 凹陷 硬滑 是
3 青绿 蜷缩 沉闷 清晰 凹陷 硬滑 是
4 浅白 蜷缩 浊响 清晰 凹陷 硬滑 是
5 青绿 稍蜷 浊响 清晰 稍凹 软粘 是
6 乌黑 稍蜷 浊响 稍糊 稍凹 软粘 是
7 乌黑 稍蜷 浊响 清晰 稍凹 硬滑 是
8 乌黑 稍蜷 沉闷 稍糊 稍凹 硬滑 否
9 青绿 硬挺 清脆 清晰 平坦 软粘 否
10 浅白 硬挺 清脆 模糊 平坦 硬滑 否
11 浅白 蜷缩 浊响 模糊 平坦 软粘 否
12 青绿 稍蜷 浊响 稍糊 凹陷 硬滑 否
13 浅白 稍蜷 沉闷 稍糊 凹陷 硬滑 否
14 乌黑 稍蜷 浊响 清晰 稍凹 软粘 否
15 浅白 蜷缩 浊响 模糊 平坦 硬滑 否
16 青绿 蜷缩 沉闷 稍糊 稍凹 硬滑 否
我们训练和测试都使用它。
读入数据:
def loaddataset(Filename):
fp = open(Filename)
a = fp.readlines()
fp.close()
dataset = []
for i in a[1:]:
b = i.strip().split()
dataset.append(b[1:])
#返回数据和属性标签
return dataset, a[0].strip().split()[1:]
dataset显示如下:
分类标签显示如下:
['色泽', '根蒂', '敲击', '纹理', '脐部', '触感', '好瓜']
统计各个属性取值的正例个数比例和反例个数比例:
def statistics(dataset, n):
#记录统计结果
count = {}
for i in dataset:
if i[n] not in count:
#列表第一个位置为正例个数,第二个位置是反例个数
if i[-1] == '是':
count[i[n]] = [1, 0]
else:
count[i[n]] = [0, 1]
else:
if i[-1] == '是':
count[i[n]][0] += 1
else:
count[i[n]][1] += 1
#计算各个属性取值为正例的概率和反例的概率
for i in count:
n = count[i][0] + count[i][1]
count[i][0] = count[i][0] / n
count[i][1] = count[i][1] / n
return count
该函数每次只统计一个属性的情况,我们以色泽为例 ,其统计结果为
{'青绿': [0.5, 0.5], '乌黑': [0.6666666666666666, 0.3333333333333333], '浅白': [0.2, 0.8]}
我使用列表保存所有属性的统计情况:
count_sum = []
for i in range(len(dataset[0])-1):
count_sum.append(statistics(dataset, i))
统计数据集中正反例的个数:
a = list(np.array(dataset)[:,-1])
y = a.count('是')
n = a.count('否')
预测:
#记录正确预测的个数
rightcount = 0
for i in range(len(dataset)):
#记录分为正类的概率
py = 1
#记录分为反类的概率
pn = 1
for j in range(len(dataset[i])-1):
b = count_sum[j]
py *= b[dataset[i][j]][0]
pn *= b[dataset[i][j]][1]
py *= y / (y + n)
pn *= n / (y + n)
if py >= pn:
flag = '是'
else:
flag = '否'
if flag == a[i]:
rightcount += 1
print('%s %s'%(flag, a[i]))
print("正确率为%s"%(rightcount / len(dataset)))
预测结果如下:
是 是
是 是
是 是
是 是
是 是
是 是
否 是
是 是
否 否
否 否
否 否
否 否
否 否
否 否
是 否
否 否
否 否
正确率为0.8823529411764706
[Finished in 0.4s]
完整代码如下,数据集和原文件已上传至我的资源https://download.csdn.net/download/qq_41398808/11242762:
import numpy as np
def loaddataset(Filename):
fp = open(Filename)
a = fp.readlines()
fp.close()
dataset = []
for i in a[1:]:
b = i.strip().split()
dataset.append(b[1:])
#返回数据和属性标签
return dataset, a[0].strip().split()[1:]
def statistics(dataset, n):
#记录统计结果
count = {}
for i in dataset:
if i[n] not in count:
#列表第一个位置为正例个数,第二个位置是反例个数
if i[-1] == '是':
count[i[n]] = [1, 0]
else:
count[i[n]] = [0, 1]
else:
if i[-1] == '是':
count[i[n]][0] += 1
else:
count[i[n]][1] += 1
#计算各个属性取值为正例的概率和反例的概率
for i in count:
n = count[i][0] + count[i][1]
count[i][0] = count[i][0] / n
count[i][1] = count[i][1] / n
return count
if __name__ == '__main__':
dataset, labelset = loaddataset('watermelon2.0.data')
count_sum = []
for i in range(len(dataset[0])-1):
count_sum.append(statistics(dataset, i))
a = list(np.array(dataset)[:,-1])
y = a.count('是')
n = a.count('否')
#记录正确预测的个数
rightcount = 0
for i in range(len(dataset)):
#记录分为正类的概率
py = 1
#记录分为反类的概率
pn = 1
for j in range(len(dataset[i])-1):
b = count_sum[j]
py *= b[dataset[i][j]][0]
pn *= b[dataset[i][j]][1]
py *= y / (y + n)
pn *= n / (y + n)
if py >= pn:
flag = '是'
else:
flag = '否'
if flag == a[i]:
rightcount += 1
print('%s %s'%(flag, a[i]))
print("正确率为%s"%(rightcount / len(dataset)))