Python手工实现朴素贝叶斯分类及预测

  • 朴素贝叶斯的简单介绍

朴素贝叶斯是基于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}

  • 2
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值