Python手工实现朴素贝叶斯分类及预测
朴素贝叶斯的简单介绍
例题及代码实现
下面例题为《人工智能数学基础》第八章的第一道习题
职业 |
症状 |
类别 |
护士 |
打喷嚏 | 感冒 |
农夫 |
打喷嚏 | 过敏 |
建筑工人 |
头痛 |
脑震荡 |
建筑工人 | 头痛 | 感冒 |
教师 | 打喷嚏 | 感冒 |
教师 |
头痛 | 脑震荡 |
职业 |
症状 |
类别 |
护士 |
打喷嚏 | 感冒 |
建筑工人 | 头痛 | 感冒 |
教师 | 打喷嚏 | 感冒 |
职业 |
症状 |
类别 |
农夫 |
打喷嚏 | 过敏 |
建筑工人 |
头痛 |
脑震荡 |
教师 |
头痛 | 脑震荡 |
首先来手算一部分来加深对公式的理解:
(1)设
为感冒,
为过敏,
为脑震荡
则不知道任何信息情况下的先验概率为
(2)设特征 为"职业为建筑工人",则患感冒的人为建筑工人的似然概率
类似的,设特征 为"症状为打喷嚏",则感冒的人打喷嚏的似然概率
(3)此时,打喷嚏且为建筑工人的人患感冒的概率为 。类似的,可以算出脑震荡和过敏的后验概率。
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}