核心:贝叶斯定理+条件独立性假设。
其中,为特征向量,y为数据类别。
贝叶斯分类问题可描述为:对特征向量为的数据项进行分类。即对于给定的输入X,计算该数据项对每个类别的后验概率
,将后验概率最大的类作为X的分类输出。
后验概率的计算即根据贝叶斯定理,有:
a.分母可由全概率公式展开为
b.分子部分为复杂的条件概率乘法,朴素贝叶斯作了条件独立性假设,即认为样本的各维特征都是独立的(由于这是一 个较强的假设,朴素贝叶斯也由此得名),所以分子可化为
这样,朴素贝叶斯分类的基本公式即为
注意到,分母对于所有的类别都是相同的,我们要找出最大概率对应的类别,只考虑分子即可,
所以,分类器即为
在计算概率时,可能出现概率为0的情况,如某个离散型随机变量观测值的某一维并未在训练集中出现,则其条件概率为0,导致对应类别的后验概率为0,失去了观测的条件,这是不合理的,会使分类产生偏差。为此,需进行一定的平滑处理。
方法如下,对每个类别中的观测样本数加上一个常数。
先验概率:
条件概率:
当lambda=1时,称为拉普拉斯平滑(Laplace smoothing).在统计学上,将这种估计方法称为贝叶斯估计。
来自http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html
下面是一组人类身体特征的统计资料:
性别 | 身高(英尺) | 体重(磅) | 脚掌(英寸) |
男 | 6 | 180 | 12 |
男 | 5.92 | 190 | 11 |
男 | 5.58 | 170 | 12 |
男 | 5.92 | 165 | 10 |
女 | 5 | 100 | 6 |
女 | 5.5 | 150 | 8 |
女 | 5.42 | 130 | 7 |
女 | 5.75 | 150 | 9 |
已知某人身高6英尺、体重130磅,脚掌8英寸,请问该人是男是女?
解:根据朴素贝叶斯分类器,计算下面两个式子的值,比较大小即可。
此人为男性概率: P(男) x P(身高|男) x P(体重|男) x P(脚掌|男)
此人为女性概率: P(女) x P(身高|女) x P(体重|女) x P(脚掌|女)
a.先验概率P(男)和P(女)即为训练数据中,男性样本和女性样本的占比。
b.这里的困难在于,由于身高、体重、脚掌都是连续变量,不能采用离散变量的方法计算概率。而且由于样本太少,所以也无法分成区间计算。怎么办?
这时,可以假设男性和女性的身高、体重、脚掌都是正态分布,通过样本计算出均值和方差,也就是得到正态分布的密度函数。有了密度函数,就可以把值代入,算出某一点的密度函数的值(也即常用的高斯型朴素贝叶斯算法GaussianNB)。
比如,男性的身高是均值5.855、方差0.035的正态分布。所以,男性的身高为6英尺的概率的相对值等于1.5789(大于1并没有关系,因为这里是密度函数的值,只用来反映各个值的相对可能性)。
将所需的先验概率和条件概率计算出来后,即可计算出性别的分类结果:
男性:P(身高=6|男) x P(体重=130|男) x P(脚掌=8|男) x P(男)
= 6.1984 x e-9
女性:P(身高=6|女) x P(体重=130|女) x P(脚掌=8|女) x P(女)
= 5.3778 x e-4
可以看到,女性的概率比男性高,所以判断该人为女性。
使用鸢尾花数据集,将数据集存为txt文件,与程序文件放在同一目录下。
代码如下:
# -*- coding:utf-8 -*-
import numpy as np
# 鸢尾花的特征作为数据
# 当使用numpy中的loadtxt函数导入该数据集时,假设数据类型dtype为浮点型,但是很明显数据集的第五列的数据类型是字符串并不是浮点型。
# 因此需要额外做一个工作,即通过loadtxt()函数中的converters参数将第五列通过转换函数映射成浮点类型的数据。
# 首先,我们要写出一个转换函数,将不同类别标签与数字相对应
def iris_type(s):
class_label={b'Iris-setosa':0,b'Iris-versicolor':1,b'Iris-virginica':2}
return class_label[s]
#使用numpy中的loadtxt读入数据文件
filepath='iris_data.txt' # 数据文件路径
data=np.loadtxt(filepath,dtype=float,delimiter=',',converters={4:iris_type})
# 将数据随机分成训练集与测试集
def splitData(trainPrecent=0.7):
train = []
test = []
for i in data:
(train if np.random.random() < trainPrecent else test).append(i)
return np.array(train), np.array(test)
trainData, testData = splitData()
print("共有%d条数据,分解为%d条训练集与%d条测试集" % (len(data), len(trainData), len(testData)))
clf = set(trainData[:, -1]) # 读取每行最后一个数据,用set得出共有几种分类,本例为1.0,2.0,3.0
trainClfData = {} # 有于存储每个类别的均值与标准差
for x in clf:
clfItems = np.array(list(filter(lambda i: i[-1] == x, trainData)))[:, :-1] # 从训练集中按类别过滤出记录
mean = clfItems.mean(axis=0) # 计算每个属性的平均值
stdev = np.sqrt(np.sum((clfItems - mean) ** 2, axis=0) / float(len(clfItems) - 1)) # 计算每个属性的标准差
trainClfData[x] = np.array([mean, stdev]).T # 对每个类形成固定的数据格式[[属性1均值,属性1标准差],[属性2均值,属性2标准差]]
# print(trainClfData)
result = []
for testItem in testData:
itemData = testItem[0:-1] # 得到训练的属性数据
itemClf = testItem[-1] # 得到训练的分类数据
prediction = {} # 用于存储单条记录集对应的每个类别的概率
for clfItem in trainClfData:
# 测试集中单条记录的每个属性在与训练集中进行比对应用的朴素贝叶斯算法,
probabilities = np.exp(
-1 * (testItem[0:-1] - trainClfData[clfItem][:, 0]) ** 2 / (trainClfData[clfItem][:, 1] ** 2 * 2)) / (
np.sqrt(2 * np.pi) * trainClfData[clfItem][:, 1])
# 将每个属性的概率相乘,等到最终该类别的概率
clfPrediction = 1
for proItem in probabilities:
clfPrediction *= proItem
prediction[clfItem] = clfPrediction
# 取得最大概率的那个类别
maxProbablity = None
for x in prediction:
if maxProbablity == None or prediction[x] > prediction[maxProbablity]:
maxProbablity = x
# 将计算的数据返回,后面有一句print我关闭了,打开就可以看到这些结果
result.append({'数据': itemData.tolist()
, '实际分类': itemClf
, '各类别概率': prediction
, '测试分类(最大概率类别)': maxProbablity
, '是否正确': 1 if itemClf == maxProbablity else 0})
rightCount = 0;
for x in result:
rightCount += x['是否正确']
print(x) #打印出每条测试集计算的数据
print('共%d条测试数据,测试正确%d条,正确率%2f:' % (len(result), rightCount, rightCount / len(result)))
1.李航,《统计学习方法》
2.https://blog.csdn.net/cxmscb/article/details/69267326
3.http://www.ruanyifeng.com/blog/2013/12/naive_bayes_classifier.html
4.https://www.cnblogs.com/pinard/p/6074222.html
5.http://sklearn.apachecn.org/cn/0.19.0/modules/naive_bayes.html
6.https://www.cnblogs.com/bqtang/p/3693827.html
7.http://www.cnblogs.com/shenxiaolin/p/8854838.html
8.https://blog.csdn.net/carmelcarmen/article/details/79250551