先验概率:对于某一个概率事件,我们都会有基于自己已有的知识,对于这个概率事件会分别以什么概率出现各种结果会有一个预先的估计,而这个估计并未考虑到任何相关因素。
对于分类数据来说,先验概率就是取某一类的概率。
(基于自己已有的知识->已有的数据)
(预先的估计->统计概率)
假如你考试没及格,老师要求大家拿卷子回家给爸妈签字,假如你考试没及格过10次,你每次都用小本记下来后果:
那么先验概率:
后验概率:在先验概率的基础上加了一层“考虑”:结合我们已有的知识,将与待检验事件(即我们正在估计概率的随机事件)相关的因素也考虑进去后,我们对随机事件的概率的预估。
我的理解是,通过结果估计条件。就西瓜数据集来说,结果是好瓜还是坏瓜,条件是色泽,敲声等等的属性,所以后验概率就是,我们已经知道这个西瓜是好瓜了,在他是好瓜的前提下估计他的色泽时青绿的概率,即P(青绿|好瓜),用字符表示就是P(x | c)。
那么,落实到实际的问题当中,我们想获得的核心结果其实也就是P(c|x),即在x数据集上,是好瓜的概率P(c=好瓜|x)和是坏瓜P(c=坏瓜|x)的概率,通过贝叶斯公式:
即可通过P(x | c)求得P(c | x),但是,求P(x | c)并不容易,所以引出下面的朴素贝叶斯。
详细分析后验概率看这篇博文吧:
朴素贝叶斯分类器(Naive Bayesian Classifier)
朴素贝叶斯方法是基于贝叶斯定理的一组有监督学习算法
朴素->所有属性相互独立,就西瓜数据集来说,颜色与敲声没有任何关系。(实际情况下是有联系的,但是为了简化,假设他们没关系)
公式:
公式中的P(x)可以忽略。
因为这个公式最后求出来的是一个数,比如西瓜数据集,我们最后求出的是P(c=好瓜 | X)=0.4
P(c=坏瓜 | X)=0.8,然后通过比较这两个数的大小来判断测试集是好瓜还是坏瓜。
P(x)在计算P(c=好瓜 | X)和P(c=坏瓜 | X)都有,而且相同。所以去掉P(x)并不影响
P(c=好瓜 | X)和P(c=坏瓜 | X)之间的大小关系。
分类准则:
思路:
具体分析还请看:朴素贝叶斯分类器(Naive Bayesian Classifier)
假设我们有了一个数据集D,那么p( c )的获得其实也较为简单:计算D中c的各个情况出现的频率即可。(这里用到了大数定律:当训练集包含充足的独立同分布样本时,P( c )可通过各类样本出现的频率来进行估计。)
朴素贝叶斯+拉普拉斯修正实现代码:
"""
利用打网球数据集PlayTenis构建决策树,该数据集的特性如下:
属性包括天气(outlook)、温度(temperature)、湿度(humidity)、是否有风(windy),样本个数为14。
标签为今天是否去打网球(play)。
具体数据如下:
NO. Outlook temperature humidity windy play
1 sunny hot high FALSE no
2 sunny hot high TRUE no
3 overcast hot high FALSE yes
4 rainy mild high FALSE yes
5 rainy cool normal FALSE yes
6 rainy cool normal TRUE no
7 overcast cool normal TRUE yes
8 sunny mild high FALSE no
9 sunny cool normal FALSE yes
10 rainy mild normal FALSE yes
"""
# 读入数据函数 返回正例,反例,总例,数据
def readFile():
f = open('D:\\PythonProject_Class\\test_Data\\PlayTennis.txt', 'r')
lk = 10
preData = [[] for i in range(lk)]
dict_PlusFeatures = {} # 保存属性的名称,并为求信息增益做准备,也就是把初值赋值为0
dict_NegativeFeatures = {} # 上一个保存的是正例,这个保存的的是反例
sum_Features = {}
for i in range(0, 4): # 把前几行的文字描述跳过
s = f.readline()
s = f.readline() # 读入属性
# NO. Outlook temperature humidity windy play
# strip函数是去除这行的开头和结尾的换行符和空格的
s = s.strip('\n')
s = s.strip(' ')
x = s.split(' ')
# 初始化字典
for i in range(1, len(x)): # 从1开始是要跳过NO.
if x[i] == 'play':
dict_PlusFeatures[x[i]] = 0
dict_NegativeFeatures[x[i]] = 0
sum_Features[x[i]] = 0
elif x[i] != '':
dict_PlusFeatures[x[i]] = {}
dict_NegativeFeatures[x[i]] = {}
sum_Features[x[i]] = {}
ls = [i for i in dict_PlusFeatures.keys()] # 提取字典中的特征名称
ls.pop(len(ls) - 1) # 去掉play
# s=set()不能kidls=[s for i in range(len(ls))],这样列表中的一个集合改变,其他的也会改变
# kidls = [set() for i in range(len(ls))] # 保存每个特征的属性值,使用没有重复元素的集合set
flag = 0 # 用于标记是正例还是反例
index = 0 # 用于指向 保存所有读入数据的predata 的下标
for i in range(lk):
cnt = 0
s = f.readline() # 读入属性
s = s.strip('\n')
s = s.strip(' ')
x = s.split(' ')
if x[len(x) - 1] == 'no': # 首先处理是正例还是反例,同时统计正反例个数
flag = -1
dict_NegativeFeatures['play'] += 1
elif x[len(x) - 1] == 'yes':
flag = 1
dict_PlusFeatures['play'] += 1
sum_Features['play'] += 1
for j in range(2, len(x) - 1): # 跳过编号以及最后的正反例
if x[j] != '':
if flag == 1:
if x[j] not in dict_PlusFeatures[ls[cnt]].keys():
dict_PlusFeatures[ls[cnt]][x[j]] = 1
else:
dict_PlusFeatures[ls[cnt]][x[j]] += 1
elif flag == -1:
if x[j] not in dict_NegativeFeatures[ls[cnt]].keys():
dict_NegativeFeatures[ls[cnt]][x[j]] = 1
else:
dict_NegativeFeatures[ls[cnt]][x[j]] += 1
if x[j] not in sum_Features[ls[cnt]].keys():
sum_Features[ls[cnt]][x[j]] = 1
else:
sum_Features[ls[cnt]][x[j]] += 1
# kidls[cnt].add(x[j])
preData[index].append(x[j])
cnt += 1
preData[index].append(x[len(x) - 1])
index += 1
for i in dict_PlusFeatures.keys():
if i != 'play':
for j in dict_PlusFeatures[i].keys():
if j not in dict_NegativeFeatures[i].keys():
dict_NegativeFeatures[i][j] = 0
for i in dict_NegativeFeatures.keys():
if i != 'play':
for j in dict_NegativeFeatures[i].keys():
if j not in dict_PlusFeatures[i].keys():
dict_PlusFeatures[i][j] = 0
preData.insert(0, ls) # 在split中发现需要表头
preData[0].append('play')
return dict_PlusFeatures, dict_NegativeFeatures, sum_Features, preData
def method(dict_PlusFeatures, dict_NegativeFeatures, sum_Features, preData):
dict_PlusFeatures['play'] = dict_PlusFeatures['play'] / sum_Features['play']
dict_NegativeFeatures['play'] = dict_NegativeFeatures['play'] / sum_Features['play']
for i in dict_PlusFeatures:
if i != 'play':
for j in dict_PlusFeatures[i]:
dict_PlusFeatures[i][j] = (dict_PlusFeatures[i][j] + 1) / (
dict_PlusFeatures['play'] + len(dict_PlusFeatures[i]))
for i in dict_NegativeFeatures:
if i != 'play':
for j in dict_NegativeFeatures[i]:
dict_NegativeFeatures[i][j] = (dict_NegativeFeatures[i][j] + 1) / (
dict_NegativeFeatures['play'] + len(dict_NegativeFeatures[i]))
for i in range(1, len(preData)):
ls = [dict_PlusFeatures['play'], dict_NegativeFeatures['play']]
for j in range(len(preData[0]) - 1):
ls[0] *= dict_PlusFeatures[preData[0][j]][preData[i][j]]
ls[1] *= dict_NegativeFeatures[preData[0][j]][preData[i][j]]
key = ls.index(max(ls))
if key == 0 and preData[i][-1] == 'yes':
print("数据{}预测正确".format(i))
elif key == 1 and preData[i][-1] == 'no':
print("数据{}预测正确".format(i))
else:
print("数据{}预测错误".format(i))
if __name__ == '__main__':
dict_PlusFeatures, dict_NegativeFeatures, sum_Features, preData = readFile()
method(dict_PlusFeatures, dict_NegativeFeatures, sum_Features, preData)