朴素贝叶斯的简单介绍
朴素贝叶斯是基于1、最大后验概率和 2、特征条件独立假设 的分类方法,其分类原理是根据某对象的先验概率和类概率计算出其后验概率,然后选择具有最大后验概率的类作为该对象所属的类别。
朴素贝叶斯分类器的公示如下:
假设某样本X具有n项特征,分别F1,F2,...,Fn。有m个类别,分别为C1,C2,...Cm。贝叶斯分类器就是计算出样本X地后验概率最大的分类,即求下面这个公式的最大值。
由于等式右边的分母部分对于每个类别C1,C2,C3...都相同,可以省略。所以贝叶斯分类的最大后验估计为求下面公式的最大值:
为了模型简单理解,朴素贝叶斯假设所有的特征都彼此独立,因此才被称之为朴素(naive)。
等号右边P(Ci)表示该类的先验概率,P(F|Ci)是类条件概率,即似然概率,表面在类别Ci中特征F的可能性。
例题及代码实现
下面例题为《人工智能数学基础》第八章的第一道习题
数据包含三种类别,分别是{感冒、过敏、脑震荡},训练数据如下表所示。预测一个打喷嚏的建筑工人诊断结果如何?
职业 | 症状 | 类别 |
护士 | 打喷嚏 | 感冒 |
农夫 | 打喷嚏 | 过敏 |
建筑工人 | 头痛 | 脑震荡 |
建筑工人 | 头痛 | 感冒 |
教师 | 打喷嚏 | 感冒 |
教师 | 头痛 | 脑震荡 |
首先来手算一下,根据病人是否感冒可将表格分为以下两部分
感冒的病人:
职业 | 症状 | 类别 |
护士 | 打喷嚏 | 感冒 |
建筑工人 | 头痛 | 感冒 |
教师 | 打喷嚏 | 感冒 |
非感冒的病人
职业 | 症状 | 类别 |
农夫 | 打喷嚏 | 过敏 |
建筑工人 | 头痛 | 脑震荡 |
教师 | 头痛 | 脑震荡 |
python代码实现如下
import pandas as pd
import numpy as np
def get_data():
'''获取数据,此处为直接输入,也可读取csv文件'''
df = pd.DataFrame(
[['护士', '打喷嚏', '感冒'], ['农夫', '打喷嚏', '过敏'], ['建筑工人', '头痛', '脑震荡'],
['建筑工人', '头痛', '感冒'], ['教师', '打喷嚏', '感冒'], ['教师', '头痛', '脑震荡']],
columns=['职业', '症状', '类别'])
return (df)
def test_data(): #获取测试数据,也可读取csv文件
df = pd.DataFrame([['建筑工人', '打喷嚏']], columns=['职业', '症状'])
return df
class NBClassify(object):
'''创建一个实现朴素贝斯模型的类'''
def __init__(self):
_tagProbablity = None #使用字典tagProbablity记录各类别的先验概率
_featuresProbablity = None #字典featureProbablity记录类别下各特征取值的条件概率
def train(self, df):
'''传入训练数据df,计算条件概率'''
# 计算每种类别的先验概率并输出
self._tagProbablity = dict(df['类别'].value_counts(normalize=True))
print('各类别的先验概率:\n', self._tagProbablity, '\n')
# 计算各特征及取值出现的次数,例如{'职业'{'护士':1, '农夫':1, ...}
dictFeaturesBase = {}.fromkeys(df.columns)
for column in df.columns:
SeriesFeature = dict(df[column].value_counts())
dictFeaturesBase[column] = SeriesFeature
del dictFeaturesBase['类别'] #删除类别信息
# print('各特征取值出现次数:\n', dictFeaturesBase)
# 初始化字典dictFeatures
# 格式{'感冒':{'职业':{'建筑工人':0, '教师':0...},{'症状':...}}'脑震荡':...}
dictFeatures = {}.fromkeys(df['类别']) #第一层字典{感冒:None,脑震荡:None...}
for key in dictFeatures.keys():
dictFeatures[key] = {}.fromkeys(
dictFeaturesBase) #第二层字典{'感冒': {'职业': None, '症状': None}...}
for key, value in dictFeatures.items():
for subkey in value.keys():
value[subkey] = {}.fromkeys(dictFeaturesBase[subkey],
0) # 第三层字典,初始值设为0
# print('dictFeature:\n', dictFeatures) #编写代码时方便理解和调试,可转换成代码执行
# 计算各类别,特征值及出现次数,存入字典dictFeatures中
for i in range(0, len(df)):
label = df.iloc[i]['类别']
for feature in df.columns[:-1]:
fvalue = df.iloc[i][feature]
dictFeatures[label][feature][fvalue] += 1
# print(dictFeatures)
#计算似然概率
for tag, featuresDict in dictFeatures.items():
for featureName, featureValueDict in featuresDict.items():
totalCount = sum(featureValueDict.values())
for featureKey, featureValues in featureValueDict.items():
featureValueDict[featureKey] = featureValues / totalCount
self._featuresProbablity = dictFeatures
print('每种特征的似然概率\n:', dictFeatures, '\n')
def predict(self, test_data):
for i in range(0, len(test_data)): # 遍历测试数据
probability = self._tagProbablity # 先验概率
for key in probability:
for column in test_data.columns:
# 先验概率 * Π似然概率
probability[key] = probability[
key] * self._featuresProbablity[key][column][
test_data[column][i]]
print(f'第{i+1}位患者的后验概率:', probability)
if __name__ == '__main__':
'''执行主程序'''
data = get_data() #获取训练数据
test_data = test_data()
model = NBClassify() #定义朴素贝叶斯模型
model.train(data)
model.predict(test_data)
执行结果为
各类别的先验概率:
{'感冒': 0.5, '脑震荡': 0.3333333333333333, '过敏': 0.16666666666666666}
每种特征的似然概率
: {'感冒': {'职业': {'建筑工人': 0.3333333333333333, '教师': 0.3333333333333333, '护士': 0.3333333333333333, '农夫': 0.0}, '症状': {'打喷嚏': 0.6666666666666666, '头痛': 0.3333333333333333}}, '过敏': {'职业': {'建筑工人': 0.0, '教师': 0.0, '护士': 0.0, '农夫': 1.0}, '症状': {'打喷嚏': 1.0, '头痛': 0.0}}, '脑震荡': {'职业': {'建筑工人': 0.5, '教师': 0.5, '护士': 0.0, '农夫': 0.0}, '症状': {'打喷嚏': 0.0, '头痛': 1.0}}}
第1位患者的后验概率: {'感冒': 0.1111111111111111, '脑震荡': 0.0, '过敏': 0.0}