说明
贝叶斯定理
有事件A、事件B,其中事件B有
B
1
,
B
2
,
.
.
.
,
B
n
{B_1,B_2,...,B_n}
B1,B2,...,Bn个互不相交的事件组成。
若我们要估计
P
(
B
i
∣
A
)
P(B_i|A)
P(Bi∣A)发生的概率,那么我们根据条件概率公式
P
(
B
i
∣
A
)
=
P
(
B
i
,
A
)
P
(
A
)
P(B_i|A)=\frac{P(B_i,A)}{P(A)}
P(Bi∣A)=P(A)P(Bi,A)
其中,
P
(
A
)
=
∑
i
=
1
n
P
(
A
∣
B
i
)
P
(
B
i
)
P(A)=\sum_{i=1}^{n}P(A|B_i)P(B_i)
P(A)=∑i=1nP(A∣Bi)P(Bi)
P
(
B
i
,
A
)
=
P
(
A
∣
B
i
)
P
(
B
i
)
P(B_i,A)=P(A|B_i)P(B_i)
P(Bi,A)=P(A∣Bi)P(Bi)
故有
P
(
B
i
∣
A
)
=
P
(
A
∣
B
i
)
P
(
B
i
)
∑
i
=
1
n
P
(
A
∣
B
i
)
P
(
B
i
)
P(B_i|A)=\frac{P(A|B_i)P(B_i)}{\sum_{i=1}^{n}P(A|B_i)P(B_i)}
P(Bi∣A)=∑i=1nP(A∣Bi)P(Bi)P(A∣Bi)P(Bi)
这就是所谓的贝叶斯公式
朴素贝叶斯
朴素贝叶斯是基于贝叶斯定理与特征田间独立假设而进行学习的模型。
朴素贝叶斯有一个较强的前提条件:各个特征之间是独立的。
他的思想是利用贝叶斯定理来学习到数据的分布,属于生成模型的一种。他根据期望风险最小化推导出后验概率最大化,故B可以用极大似然估计和贝叶斯估计来找到模型的参数。
具体来说:假设
Y
Y
Y是我们的类别分布,
X
X
X是我们已有的数据。我们在预测新的样本
x
x
x属于哪个类别时,做的工作就是计算
P
(
Y
k
∣
x
)
P(Y_k|x)
P(Yk∣x),其中
k
_k
k就是
Y
Y
Y的类别个数。因此我们就需要学习联合概率分布
P
(
Y
,
X
)
P(Y,X)
P(Y,X)。学习出来了联合概率分布,我们就可以给一个输入的
x
x
x预测出其所属的类别
y
y
y。
条件独立性假设
P
(
X
=
x
∣
Y
=
Y
k
)
=
∏
j
=
1
m
P
(
x
j
∣
Y
=
Y
k
)
P(X=x|Y=Y_k) = \prod_{j=1}^mP(x^j|Y=Y_k)
P(X=x∣Y=Yk)=j=1∏mP(xj∣Y=Yk)
m是指的x的特征数量
这里写的不是很好,对概率的知识了解的还是很浅,具体的推理可以看李航博士《统计学习方法》
Python实现代码
#!/usr/bin/python
# -*- coding:utf-8 -*-
"""
Author LiHao
Time 2018/11/2 16:17
"""
import os
import sys
import numpy as np
from dataset.dataUtils import load_mnist
from ml_learn.algorithm.base import Algorithm #自己写的一个抽象类
class NativeBayes(Algorithm):
def __init__(self,nb_lambda = 0):
#每个参数的概率
self._parameters_prop = {}
#类别名称及各个类别的概率
self._labels_prop = {}
#拉普拉斯平滑参数
self._lambda = nb_lambda
#类别前缀
self._label_prefix = "C"
#参数及特征前缀
self._parameters_predix = "P"
#训练数据总数
self._data_num = 0
#类别名称列表
self._label_name_list = None
#特征的取值集合,为map(set)嵌套
self._features_set = {}
def predict(self,x):
"""
预测
:param x:
:return:
"""
dx,fy = x.shape
for i in range(dx):
max_class_name = ""
max_class_prop = 0.0
for class_name,class_prop in self._labels_prop.items():
likehood_prop = 1.0
for j in range(fy):
current_data_name = self._parameters_predix + str(j) + "_" + str(x[i][j]) + "|" + class_name
if self._parameters_prop.get(current_data_name) is not None:
likehood_prop *= self._parameters_prop.get(current_data_name)
else:
likehood_prop *= 0.001
current_prop = class_prop * likehood_prop
if current_prop >= max_class_prop:
max_class_prop = current_prop
max_class_name = class_name
print("The ",i,"'s data class is ",max_class_name," max prop is ",max_class_prop)
def train(self,X,Y):
"""
训练-贝叶斯估计方法
:param X:
:param Y:
:return:
"""
data_num,feature_num = X.shape
self._data_num = data_num
label_list = []
for i in range(data_num):
#读入类别标签
label_name = self._label_prefix+str(Y[i])
if self._labels_prop.__contains__(label_name):
self._labels_prop[label_name] += 1
else:
self._labels_prop[label_name] = 1
label_list.append(label_name)
for j in range(feature_num):
feature_name = self._parameters_predix+str(j)
if self._features_set.__contains__(feature_name):
self._features_set[feature_name].add(str(X[i][j]))
else:
self._features_set[feature_name] = set([str(X[i][j])])
current_data_name = self._parameters_predix+str(j)+"_"+str(X[i][j])+"|"+label_name
if self._parameters_prop.__contains__(current_data_name):
self._parameters_prop[current_data_name] += 1
else:
self._parameters_prop[current_data_name] = 1
self._label_name_list = label_list
#求参数的概率值
for key,value in self._parameters_prop.items():
belong_class = key.split("|")[-1]
belong_feature_name = key.split("_")[0]
#数据的每个特征维度值的种类个数
Sj = len(self._features_set[belong_feature_name])
class_num = self._labels_prop[belong_class]
self._parameters_prop[key] = (value*1.0+self._lambda)/(class_num+self._lambda*Sj)
#求每个类别的概率值
for key,value in self._labels_prop.items():
self._labels_prop[key] = (value*1.0 + self._lambda)/(data_num + len(self._labels_prop)*self._lambda)
print("LH -*- Train Done.")
def bayes_test():
"""
这是用的李航博士书P50上的例子
其中第二个维度取值是S M L 我把它们变成了1 2 3
得到结果和书上的结果是一致的
nb_lambda = 0为极大似然估计 >0是贝叶斯估计
"""
X = np.array([[1,1],[1,2],[1,2],[1,1],[1,1],[2,1],[2,2],[2,2],[2,3],[2,3],[3,3],[3,2],[3,2],[3,3],[3,3]])
Y = np.array([[-1],[-1],[1],[1],[-1],[-1],[-1],[1],[1],[1],[1],[1],[1],[1],[-1]])
T = np.array([[2,1]])
import time
start1 = time.time()
clf = NativeBayes(nb_lambda=0)
clf.train(X,Y)
clf.predict(T)
end1 = time.time()
print(end1-start1)
if __name__ == '__main__':
bayes_test()
这里用了李航《统计学习方法》中的例子来测试,证明其准确性
load_mnist函数 见我的另一篇博客中写的KNN手写数字分类
我也用上面得到的数据集做了朴素贝叶斯分类,但效果还不如KNN。部分原因是每一维数据是0-1之间离散的数值,没有做标准化。将其变为0或1的取值应该会提升一些效果。
听说,朴素贝叶斯用在文本分类中效果不错