用Python实现朴素贝叶斯分类器(简易版)

朴素贝叶斯分类器的介绍

定义

朴素贝叶斯指的是在特征条件独立假设下, 利用贝叶斯公式来进行分类的分类方法, 其中特征条件独立假设指的是在类确定的条件下都是条件独立的.

贝叶斯定理(公式)

P ( A i ∣ B ) = P ( A i ) P ( B ∣ A i ) ∑ j = 1 n P ( A j ) P ( B ∣ A j ) P(A_i|B)=\frac{P(A_i)P(B|A_i)}{\sum_{j=1}^nP(A_j)P(B|A_j)} P(AiB)=j=1nP(Aj)P(BAj)P(Ai)P(BAi)
其中 P ( A ∣ B ) P(A|B) P(AB)是在 B B B发生的情况下 A A A发生的可能性。 A 1 , A 2 , . . . , A n A_1, A_2, ... ,A_n A1,A2,...,An为完备事件组,即 ⋃ i = 1 n A i = Ω , ⋂ i = 1 n A i = ∅ \bigcup_{i=1}^{n}A_i=\Omega,\bigcap_{i=1}^{n}A_i=\varnothing i=1nAi=Ω,i=1nAi=

优点

  • 简单
    因为有很强的特征条件独立性假设,所以计算复杂度大大降低
  • 学习和预测的效率高
    因为当学习的时候只需要根据训练数据计算相应的条件概率和先验概率,当预测的时候只需要找到匹配条件的概率值并比较大小即可

缺点

  • 因为有特征条件独立性的假设,所以该模型不太适用于具有强相关性特征的样本集的训练。换句话说,作出这样很强的假设,会在一定程度上会牺牲掉分类的准确率

代码

构造一个朴素贝叶斯分类器类, 首先将一些变量进行初始化

import pandas as pd
from functools import reduce

class NaiveBayes(object):

    def __init__(self, Data_df, _lambda=0):
        self.X_df = Data_df.iloc[:, 0:-1]   # 特征列
        self.y_df = Data_df.iloc[:, -1]     # 标签列
        self.label = set(self.y_df)         # 标签的所有可能取值
        self.col = len(self.X_df.columns)   # 记录特征的列数
        self.row = len(self.X_df)           # 记录特征的行数
        self.Label_proba = {}               # 记录每个标签值对应的特征概率
        self.label_side = {}                # 记录标签值的先验概率
        self._lambda = _lambda              # 贝叶斯估计中的lambda参数

接下来要根据训练集合计算相应的先验概率个条件概率, 并且利用字典来记录相应的概率.

    def TrainClassifier(self):
        for y_label in self.label:
            Feature_dict = {}                                                  # 记录每个特征对应的概率
            for col in range(self.col):
                feature_dict = {}                                              # 记录特征的每种取值的概率
                for feature in set(Data_df.iloc[:, col]):
                    filter_temp = Data_df[Data_df.iloc[:, -1] == y_label]      # 将y的相应取值的行过滤出来
                    proba = (sum(filter_temp.iloc[:, col] == feature) + self._lambda)/\ 
                            (len(filter_temp)+len(set(Data_df.iloc[:, col])))  # 计算每种标签值所对应的条件概率
                    proba = round(proba, 2)
                    feature_dict[feature] = proba
                Feature_dict[self.X_df.columns[col]] = feature_dict
            self.Label_proba[y_label] = Feature_dict

        for label_value in self.label:
            self.label_side[label_value] = (sum(self.y_df == label_value) +self._lambda)/\
                                           (self.row + len(self.label)*self._lambda)

然后构造一个预测函数, 目的是针对新输入的特征来进行预测, 也就是判断输入实例属于哪一类.

    def Predit(self, x_list):

        max_proba = 0
        for label_key, label_value in self.Label_proba.items():
            feature_prob = []                                       # 用来记录输入值对应的概率
            count = 0                                               # 用来计数遍历第几个特征
            for feature_key, feature_value in label_value.items():  # 遍历两个特征
                for prob_key, prob_value in feature_value.items():  # 遍历每个特征的不同取值
                    if prob_key == x_list[count]:
                        feature_prob.append(prob_value)
                count += 1
                
            post_prob = reduce(lambda x, y: x * y, feature_prob)    # 将列表中的每个元素相乘
            post_prob *= self.label_side[label_key]

            if post_prob > max_proba:
                max_proba = post_prob
                y = label_key
        return y

最后通过统计学习方法书上p63所介绍的例子, 来测试一下编写的程序是否正确吧~

if __name__ == '__main__':
    Data = [[1, 'S', -1], [1, 'M', -1], [1, 'M', 1], [1, 'S', 1], [1, 'S', -1], [2, 'S', -1], [2, 'M', -1],
           [2, 'M', 1], [2, 'L', 1], [2, 'L', 1], [3, 'L', 1], [3, 'M', 1], [3, 'M', 1], [3, 'L', 1], [3, 'L', -1]]
    Data_df = pd.DataFrame(Data, columns=['特征1', '特征2', '标签'])
    x = [2, 'S']
    NB = NaiveBayes(Data_df)
    NB.TrainClassifier()
    y_prediction = NB.Predit(x)
    print(y_prediction)

运行结果为:
朴素贝叶斯分类器预测的结果这样就实现了一个简易版本的朴素贝叶斯分类器. 之所以称为简易版本, 是因为还有很多地方可以优化, 比如

  • 输入数据的数据结构
    程序中的输入实例只能处理数据框,可以考虑数组等其他数据结构
  • 时间复杂度太高
    程序中用到了多层的for循环结构,就会大大增加了时间复杂度,可以考虑如何减少for循环来减少时间复杂度
  • 空间复杂度太高
    为了存储记录,开辟了多块内存,可以考虑换用其他的数据结构来降低空间复杂度
  • 可处理的数据类型单一
    本篇文章中涉及的程序处理的特征只能是分类变量,可以考虑将程序扩展成能够处理连续型变量的情形(ps:在sklearn中的高斯朴素贝叶斯就能够处理该类问题)

当然该模型也逃不出"sklearn", 这个可以称得上包含所有机器学习算法的库.

from sklearn.naive_bayes import MultinomialNB
import pandas as pd
import numpy as np

DataSet = [[1, 'S', -1], [1, 'M', -1], [1, 'M', 1], [1, 'S', 1], [1, 'S', -1], [2, 'S', -1], [2, 'M', -1],
           [2, 'M', 1], [2, 'L', 1], [2, 'L', 1], [3, 'L', 1], [3, 'M', 1], [3, 'M', 1], [3, 'L', 1], [3, 'L', -1]]

Data_df = pd.DataFrame(DataSet, columns=['特征1', '特征2', '标签'])
Data_df['特征2'], index = pd.factorize(Data_df['特征2'])
X_df = Data_df.iloc[:, 0:-1]
y_df = Data_df.iloc[:, -1]

clf = MultinomialNB()
clf = clf.fit(X_df, y_df)
x = np.array([2, 0]).reshape(1, -1)
y_pred = clf.predict(x)

算法

引用的书籍中已经把朴素贝叶斯算法的流程讲述得很详细了, 在这里小编就不再赘述啦~

补充

小编刚刚跨入互联网行业, 对互联网也是初窥门径. 虽然现在工作很忙, 没有太多时间来写博文, 但是和大家share自己idea的心一直都在, 所以就算时间很少也要挤时间来写, 本篇博文是小编趁着空闲时间匆忙赶出来的. 和往常一样, 小编不太爱照本宣科, 比较喜欢靠自己的理解说话, 因此文章中不免会有些描述不是很准确的词,希望大家多多包容与理解,如果能提出宝贵的意见就更好啦~ 另外, 小编还会继续加油哒!!!(ps: Python源码已经上传到小编的github)

[1] 李航. 统计学习方法(第二版). 清华大学出版社.
[2] 百度百科. https://baike.baidu.com/item/贝叶斯公式.

  • 8
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值