贝叶斯理论
贝叶斯决策论是概率框架下实施决策的基本方法。对分类任务来说,在所有相关概率都已知的理想情况下,贝叶斯决策论考虑如何基于这些概率和误判损失来选择最有的类别标记。贝叶斯推理的思维过程:在遇到一种情况时,我们会做出概率假设,然后根据这些假设更新你对这个世界的信念。
这里的问题可以描述成:
假设有两个类别w1,w2,有个样本x,要么x∈w1,要么x∈w2。求P(w1|x)和P(w2|x),且P(w1|x)+P(w2|x)=1,我们的分类问题是:
如果P(w1|x)>P(w2|x),则x属于w1类;否则x属于w2类。
这么说可能有点抽象,举个具体的例子。w1代表下雨,w2代表不下雨,现在有某一天,天空出现了乌云,代表x,这一天要么下雨,要么不下雨,P(w1|x)就是在出现乌云的情况下,下雨;P(w2|x)就是在出现乌云的情况下,不下雨。显然这两种情况的概率之和是1,反正都是这两种情况之一。所以,我们的分类问题就是,P(下雨|乌云)和P(不下雨|乌云)哪个概率大,哪个概率大,我们就认为结果属于哪一类。
贝叶斯公式如下:
用我们之前的例子就是P(下雨|乌云)= P(下雨)P(乌云|下雨)/ P(乌云)
朴素贝叶斯
朴素贝叶斯其实就在贝叶斯公式的条件下增加了一个限制。那就是所有的属性条件相互独立。用我们之前“是否去打高尔夫球”的例子来说,就是认为天气、温度、湿度、是否有风这几个属性相互独立,当然现实中这几个条件不可能完全独立,所以朴素贝叶斯其实是对贝叶斯方法进行了简化,这也就是它被叫作朴素贝叶斯的原因。
问题:根据天气,温度,湿度,是否有风几个因素来判断是否去打高尔夫球。下面是现有的数据:
天气 | 温度 | 湿度 | 是否有风 | 是否去打高尔夫球 |
晴 | 热 | 高 | 否 | 否 |
晴 | 热 | 高 | 是 | 否 |
阴 | 热 | 高 | 否 | 是 |
雨 | 适宜 | 高 | 否 | 是 |
雨 | 冷 | 正常 | 否 | 是 |
雨 | 冷 | 正常 | 是 | 否 |
阴 | 冷 | 正常 | 是 | 是 |
晴 | 适宜 | 高 | 否 | 否 |
晴 | 冷 | 正常 | 否 | 是 |
雨 | 适宜 | 正常 | 否 | 是 |
晴 | 适宜 | 正常 | 是 | 是 |
阴 | 适宜 | 高 | 是 | 是 |
阴 | 热 | 正常 | 否 | 是 |
雨 | 适宜 | 高 | 是 | 否 |
假设有一个数据:天气:晴,温度:适宜,湿度:高,是否有风:有,想要预测是否去打高尔夫球。我们用朴素贝叶斯方法手动计算一下。
问题就是计算P(去打球|条件x)和P(不去打球|条件x),看哪个概率更大,如果去打球的概率更大就去,反之就不去打球。
P(去打球|x)=P(去打球)P(x|去打球) / P(x),P(不去打球|x)=P(不去打球)P(x|不去打球) / P(x),由于分母P(x)都一样的,所以其实就是比较P(去打球)P(x|去打球)和P(不去打球)P(x|不去打球)。
P(去打球) = 9/14, P(不去打球) = 5/14
P(晴|去) = P(天气=晴|去打球) = 2/9
P(晴|不去) = P(天气=晴|不去打球) = 3/5
P(适宜|去) = P(温度=适宜|去打球) = 4/9
P(适宜|不去) = P(温度=适宜|不去打球) = 2/5
P(高|去) = P(湿度=高|去打球) = 3/9
P(高|不去) = P(湿度=高|不去打球) = 4/5
P(有|去) = P(有风|去打球) = 3/9
P(有|不去)=P(无风|不去打球)= 3/5
所以P(去打球)P(x|去打球) = (9/14)*(2/9)*(4/9)*(3/9)*(3/9) = 0.0071
P(不去打球)P(x|不去打球) = (5/14)*(3/5)*(2/5)*(4/5)*(3/5) = 0.0411
可见,P(不去打球)P(x|不去打球)远大于P(去打球)P(x|去打球),也就是说P(不去打球|x)>>P(去打球|x),因此我们的分类结果是,不去打球。这和我决策树这边文章里面的预测结果是一致的。
下面我们通过程序来实现一下这个过程。
程序实现
首先,把这个案例中的数据保存到一个文本文件中,我们通过程序来读取这个文件:
import numpy as np
def load_data(f):
file = open(f,'r',encoding='utf-8')
arr = []
for line in file.readlines():
#print(line)
arr.append(line.strip())
return arr[1:]
print(load_data('data.txt'))
# 输出:
['晴 热 高 否 否', '晴 热 高 是 否', '阴 热 高 否 是', '雨 适宜 高 否 是',
'雨 冷 正常 否 是', '雨 冷 正常 是 否', '阴 冷 正常 是 是', '晴 适宜 高 否 否',
'晴 冷 正常 否 是', '雨 适宜 正常 否 是', '晴 适宜 正常 是 是', '阴 适宜 高 是 是',
'阴 热 正常 否 是', '雨 适宜 高 是 否']
然后根据读取到的这些数据来组成需要的样本
def get_sample(arr):
weather = []
temp = []
wet = []
wind = []
label = []
for d in arr:
li = d.split(' ')
weather.append(li[0])
temp.append(li[1])
wet.append(li[2])
wind.append(li[3])
label.append(li[4])
return (weather,temp,wet,wind,label)
arr = load_data('data.txt')
weather,temp,wet,wind,label = get_sample(arr)
这里我们可以打印出获取到的几个属性信息:
# weather:
['晴', '晴', '阴', '雨', '雨', '雨', '阴', '晴', '晴', '雨', '晴', '阴', '阴', '雨']
# temp:
['热', '热', '热', '适宜', '冷', '冷', '冷', '适宜', '冷', '适宜', '适宜', '适宜', '热', '适宜']
# wet:
['高', '高', '高', '高', '正常', '正常', '正常', '高', '正常', '正常', '正常', '高', '正常', '高']
# wind:
['否', '是', '否', '否', '否', '是', '是', '否', '否', '否', '是', '是', '否', '是']
# label:
['否', '否', '是', '是', '是', '否', '是', '否', '是', '是', '是', '是', '是', '否']
有了这些数据,我们就可以根据这些数据来计算概率,并根据这些先验知识来对未知的数据进行分类了。下面的程序和注释详细解释了计算过程:
def bayes(X, label, d):
# X:输入的训练样本数据
# label:输入的训练样本标签
# d:输入待分类的数据
label = np.array(label) # 样本标签
p_list = [] # 最终得到的概率数组,用于判断哪个概率更高
for i in np.unique(label): # 每一种标签值,这里就是“是”“否”去打高尔夫球
p=1 # 默认p=1,是为了在后面计算概率的时候需要连乘
for j in range(len(d)): # 遍历每一个属性
x = X[j] # 获取到每个属性的训练数据数组
count = 0 # 计数值
print(x)
for k in range(len(x)): # 遍历每个样本属性数组的值
# 如果样本属性的值等于测试属性值,且标签是循环遍历到的类型
if x[k] == d[j] and label[k]==i:
#print(x[k])
#print(i)
count+=1 # 计数加1
print(count)
p = p*(count/np.sum(label==i)) # 计算概率,相当于前面论述中的P(晴|不去)
print("{}/{}".format(count, np.sum(label==i))) # 打印出当时输出的概率计算公式
print(p) # 打印出概率值
# 最终还要乘上每种类型的先验概率,案例中就是P(去)和P(不去)
p = p*(np.sum(label==i)/len(label))
print(p)
p_list.append(p) # 把计算出的每类的概率存到概率数组中
print(p_list)
max_value = max(p_list) # 求列表最大值
max_idx = p_list.index(max_value) # 求最大值对应索引
print(label[max_idx]) # 打印出分类结果
下面来测试一下:
# 构建一个样本数据
X = []
X.append(weather)
X.append(temp)
X.append(wet)
X.append(wind)
# 构建一个测试数据
d = ['晴','适宜','高','是']
# 测试贝叶斯分类,label前面已经构建了
bayes(X,label,d)
输出结果如下:
['晴', '晴', '阴', '雨', '雨', '雨', '阴', '晴', '晴', '雨', '晴', '阴', '阴', '雨']
3
3/5
0.6
['热', '热', '热', '适宜', '冷', '冷', '冷', '适宜', '冷', '适宜', '适宜', '适宜', '热', '适宜']
2
2/5
0.24
['高', '高', '高', '高', '正常', '正常', '正常', '高', '正常', '正常', '正常', '高', '正常', '高']
4
4/5
0.192
['否', '是', '否', '否', '否', '是', '是', '否', '否', '否', '是', '是', '否', '是']
3
3/5
0.1152
0.04114285714285714
['晴', '晴', '阴', '雨', '雨', '雨', '阴', '晴', '晴', '雨', '晴', '阴', '阴', '雨']
2
2/9
0.2222222222222222
['热', '热', '热', '适宜', '冷', '冷', '冷', '适宜', '冷', '适宜', '适宜', '适宜', '热', '适宜']
4
4/9
0.09876543209876543
['高', '高', '高', '高', '正常', '正常', '正常', '高', '正常', '正常', '正常', '高', '正常', '高']
3
3/9
0.03292181069958847
['否', '是', '否', '否', '否', '是', '是', '否', '否', '否', '是', '是', '否', '是']
3
3/9
0.010973936899862823
0.007054673721340387
[0.04114285714285714, 0.007054673721340387]
否
可以看到对两种类别(“是”或“否”)的循环,每个循环内部,遍历了四种属性,并打印出了计数值和和概率公式,以及最终得到的概率值:[0.04114285714285714, 0.007054673721340387],和我们之前计算的结果是一样的,最终输出也是“否”,也就是不去打球。
现实中贝叶斯算法的应用非常广泛,并且朴素贝叶斯只是最简单的一种贝叶斯算法,其余包含半朴素贝叶斯算法,贝叶斯网络,EM算法等等很多,后面有时间我会继续写一下这方面的相关介绍。