• Python实现朴素贝叶斯分类器


    1.朴素贝叶斯概念

    在所有的机器学习分类算法中,朴素贝叶斯和其他绝大多数的分类算法都不同。对于大多数的分类算法,比如决策树,KNN,逻辑回归,支持向量机等,他们都是判别方法,也就是直接学习出特征输出Y和特征X之间的关系,要么是决策函数Y=f(X),要么是条件分布P(Y|X)。但是朴素贝叶斯却是生成方法,也就是直接找出特征输出Y和特征X的联合分布P(X,Y),然后用P(Y|X)=P(X,Y)/P(X)得出。
    具体算法思想过程如下图(《统计学习方法》李航,P50):
    在这里插入图片描述

    2.朴素贝叶斯算法

    根据以上公式算法,python实现朴素贝叶斯算法思想过程如下:
    我们先计算P(Y=ck)P(Y=c_k)的概率,再计算每一个特征P(xy)P(x|y)的概率得到每一列x中的特征出现概率,最终形成y_p及yx_p概率矩阵,针对新数据查询这两个概率矩阵,得到每一种Y=c_k时的概率,概率最大的那个分类就是预测结果,需要注意的是:P(cx)=P(c)P(xc)/P(x)P(c|x)=P(c)P(x|c)/P(x),同一组数据,对所有分类来说分母P(x)P(x)均相同,所已只比较分子大小即可。
    #极大似然估计 朴素贝叶斯算法,计算结果与《统计学习方法》李航,P51页一致。

    #朴素贝叶斯算法 极大似然估计,计算结果与《统计学习方法》李航,P51页一致
    def get_p_matrix(arr_data):
        # 获得y中分类标签的唯一值
        y_lables = np.unique(arr_data[:,-1]) 
        #y_lables = set(arr_data[:,-1])  # 同上,两种写法均可
        
        y_counts=len(arr_data) # y总数据条数
        y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值
        for y_lable in y_lables:
            y_p[y_lable]=len(arr_data[arr_data[:,-1]==y_lable])/y_counts  # y中每一个分类的概率(其实就是频率)
            
        yx_cnt=[] # 固定y以后的,x中每一种特征出现的次数,此数据量并不大,y分类数*x维度列数,按list存储即可
        for y_lable in y_p.keys():# 先固定y,遍历y中每一个分类
            y_lable_cnt=len(arr_data[arr_data[:,-1]==y_lable]) # 此y分类数据条数
            for x_j in range(0,arr_data.shape[1]-1): # 在固定x特征列,遍历每列x中的特征
                x_j_count=Counter(arr_data[arr_data[:,-1]==y_lable][:,x_j]) # 按列统计每种特征出现的次数,因为某一列的特征数是不固定的,所以按dict类型存储
                yx_cnt.append([y_lable,y_lable_cnt,x_j,dict(x_j_count)])
                
        yx_p=[] # 将统计次数处理为概率
        for i in range(0,len(yx_cnt)):
            #print(yx_cnt[i])
            #print(yx_cnt[i][3])
            p={} # 将每列x特征出现的次数转换为概率
            for key in yx_cnt[i][3].keys():
                p[key]=yx_cnt[i][3][key] / yx_cnt[i][1]
            yx_p.append([yx_cnt[i][0],yx_cnt[i][1],yx_cnt[i][2],p])
        return y_p,yx_p
    

    #朴素贝叶斯算法 贝叶斯估计, λ=1, k=2, s=3; λ=1 拉普拉斯平滑,计算结果与《统计学习方法》李航,P52页一致。

    #朴素贝叶斯算法   贝叶斯估计, λ=1, k=2, s=3; λ=1 拉普拉斯平滑,计算结果与《统计学习方法》李航,P52页一致。
    def get_p_matrix_laplace(arr_data):
        # 获得y中分类标签的唯一值
        y_lables = np.unique(arr_data[:,-1]) 
        #y_lables = set(arr_data[:,-1])  # 同上,两种写法均可
        lambda1=1 #λ=1 拉普拉斯平滑
        k=len(y_lables) # y分类个数k,用于拉普拉斯平滑
        
        y_counts=len(arr_data) # y总数据条数
        y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值
        for y_lable in y_lables:
            y_p[y_lable]=(len(arr_data[arr_data[:,-1]==y_lable])+lambda1)/(y_counts+k*lambda1)  # y中每一个分类的概率(其实就是频率)
            
        yx_cnt=[] # 固定y以后的,x中每一种特征出现的次数,此数据量并不大,y分类数*x维度列数,按list存储即可
        for y_lable in y_p.keys():# 先固定y,遍历y中每一个分类
            y_lable_cnt=len(arr_data[arr_data[:,-1]==y_lable]) # 此y分类数据条数,N
            for x_j in range(0,arr_data.shape[1]-1): # 在固定x特征列,遍历每列x中的特征
                x_j_count=Counter(arr_data[arr_data[:,-1]==y_lable][:,x_j]) # 按列统计每种特征出现的次数,因为某一列的特征数是不固定的,所以按dict类型存储
                yx_cnt.append([y_lable,y_lable_cnt,x_j,dict(x_j_count)])
                
        yx_p=[] # 将统计次数处理为概率
        for i in range(0,len(yx_cnt)):
            #print(yx_cnt[i])
            #print(yx_cnt[i][3])
            p={} # 将每列x特征出现的次数转换为概率
            s=len(yx_cnt[i][3].keys())
            for key in yx_cnt[i][3].keys():
                p[key]=(yx_cnt[i][3][key]+lambda1) / (yx_cnt[i][1]+s*lambda1)
            yx_p.append([yx_cnt[i][0],yx_cnt[i][1],yx_cnt[i][2],p])
        return y_p,yx_p
    

    预测结果图:
    在这里插入图片描述
    所有代码如下:

    # -*- coding: utf-8 -*-
    """
     @Time    : 2018/11/09 09:07
     @Author  : hanzi5
     @Email   : **@163.com
     @File    : NaiveBayes.py
     @Software: PyCharm
    """
    
    import numpy as np
    import pandas as pd
    #import matplotlib.pyplot as plt
    from collections import Counter
    
    # 正态分布(高斯分布)函数,输入值x,miu均值,rou方差
    def Gaussian(x,miu,rou):
        p_xc=1/(np.sqrt(2*np.pi)*rou)*np.exp(-(x-miu)**2/(2*rou**2))
        return p_xc
    
    #朴素贝叶斯算法 极大似然估计,计算结果与《统计学习方法》李航,P51页一致
    def get_p_matrix(arr_data):
        # 获得y中分类标签的唯一值
        y_lables = np.unique(arr_data[:,-1]) 
        #y_lables = set(arr_data[:,-1])  # 同上,两种写法均可
        
        y_counts=len(arr_data) # y总数据条数
        y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值
        for y_lable in y_lables:
            y_p[y_lable]=len(arr_data[arr_data[:,-1]==y_lable])/y_counts  # y中每一个分类的概率(其实就是频率)
            
        yx_cnt=[] # 固定y以后的,x中每一种特征出现的次数,此数据量并不大,y分类数*x维度列数,按list存储即可
        for y_lable in y_p.keys():# 先固定y,遍历y中每一个分类
            y_lable_cnt=len(arr_data[arr_data[:,-1]==y_lable]) # 此y分类数据条数
            for x_j in range(0,arr_data.shape[1]-1): # 在固定x特征列,遍历每列x中的特征
                x_j_count=Counter(arr_data[arr_data[:,-1]==y_lable][:,x_j]) # 按列统计每种特征出现的次数,因为某一列的特征数是不固定的,所以按dict类型存储
                yx_cnt.append([y_lable,y_lable_cnt,x_j,dict(x_j_count)])
                
        yx_p=[] # 将统计次数处理为概率
        for i in range(0,len(yx_cnt)):
            #print(yx_cnt[i])
            #print(yx_cnt[i][3])
            p={} # 将每列x特征出现的次数转换为概率
            for key in yx_cnt[i][3].keys():
                p[key]=yx_cnt[i][3][key] / yx_cnt[i][1]
            yx_p.append([yx_cnt[i][0],yx_cnt[i][1],yx_cnt[i][2],p])
        return y_p,yx_p
    
    #朴素贝叶斯算法   贝叶斯估计, λ=1  K=2, S=3; λ=1 拉普拉斯平滑,计算结果与《统计学习方法》李航,P52页一致。
    def get_p_matrix_laplace(arr_data):
        # 获得y中分类标签的唯一值
        y_lables = np.unique(arr_data[:,-1]) 
        #y_lables = set(arr_data[:,-1])  # 同上,两种写法均可
        lambda1=1 #λ=1 拉普拉斯平滑
        k=len(y_lables) # y分类个数k,用于拉普拉斯平滑
        
        y_counts=len(arr_data) # y总数据条数
        y_p={}             # y中每一个分类的概率,字典初始化为空,y分类数是不定的,按字典存储更方便取值
        for y_lable in y_lables:
            y_p[y_lable]=(len(arr_data[arr_data[:,-1]==y_lable])+lambda1)/(y_counts+k*lambda1)  # y中每一个分类的概率(其实就是频率)
            
        yx_cnt=[] # 固定y以后的,x中每一种特征出现的次数,此数据量并不大,y分类数*x维度列数,按list存储即可
        for y_lable in y_p.keys():# 先固定y,遍历y中每一个分类
            y_lable_cnt=len(arr_data[arr_data[:,-1]==y_lable]) # 此y分类数据条数,N
            for x_j in range(0,arr_data.shape[1]-1): # 在固定x特征列,遍历每列x中的特征
                x_j_count=Counter(arr_data[arr_data[:,-1]==y_lable][:,x_j]) # 按列统计每种特征出现的次数,因为某一列的特征数是不固定的,所以按dict类型存储
                yx_cnt.append([y_lable,y_lable_cnt,x_j,dict(x_j_count)])
                
        yx_p=[] # 将统计次数处理为概率
        for i in range(0,len(yx_cnt)):
            #print(yx_cnt[i])
            #print(yx_cnt[i][3])
            p={} # 将每列x特征出现的次数转换为概率
            s=len(yx_cnt[i][3].keys())
            for key in yx_cnt[i][3].keys():
                p[key]=(yx_cnt[i][3][key]+lambda1) / (yx_cnt[i][1]+s*lambda1)
            yx_p.append([yx_cnt[i][0],yx_cnt[i][1],yx_cnt[i][2],p])
        return y_p,yx_p
    
    
    if __name__ == "__main__":
        df_data=pd.read_csv('D:/python_data/naivebayes_data.csv')
        arr_data=np.array(df_data.values) # 数据处理为numpy.array类型,其实pandas.Dataframe类型更方便计算
        # 测试数据一条,x1,x2
        features = [2,'S']
        
        #1、素贝叶斯算法,极大似然估计,调用函数,计算概率矩阵
        y_p,yx_p=get_p_matrix(arr_data)
        # 查看概率矩阵
        print('1、素贝叶斯算法,极大似然估计:')
        print('y_p:
    ',y_p)
        print('yx_p:
    ',yx_p)
        
        # 朴素贝叶斯分类器,数据[2,'S']手动计算过程
        # P(c|x)=P(c)P(x|c)/P(x),同一组数据,对所有分类来说分母相同,所已只比较分子大小即可
        # c=1, 0.6*0.3333*0.1111=0.022217778
        # c=-1,0.4*0.3333*0.5=0.06666
        # 比较c=1及c=-1时概率大小,数据[2,'S']数据c=-1类
        
        yx_p_arr=np.array(yx_p) # list类型不好按列取值,转换为array类型
        # 编程计算每个分类的概率值
        res1={}
        for key in y_p.keys():
            res1[key]=1*y_p[key]
            for i in range(0,len(features)):
                res1[key]=res1[key]*yx_p_arr[(yx_p_arr[:,0]==key)&(yx_p_arr[:,2]==i)][:,3][0][features[i]]
                
        print('测试数据:',features,'各分类概率:',res1,',预测结果为:',max(res1,key=res1.get))
        
        #2、朴素贝叶斯算法,贝叶斯估计,调用函数,计算概率矩阵
        y_p_ll,yx_p_ll=get_p_matrix_laplace(arr_data)
        print('
     2、朴素贝叶斯算法,贝叶斯估计')
        print('y_p_ll:
    ',y_p_ll)
        print('yx_p_ll:
    ',yx_p_ll)
        
        yx_p_ll_arr=np.array(yx_p_ll) # list类型不好按列取值,转换为array类型
        # 编程计算每个分类的概率值
        res2={}
        for key in y_p_ll.keys():
            res2[key]=1*y_p_ll[key]
            for i in range(0,len(features)):
                res2[key]=res2[key]*yx_p_ll_arr[(yx_p_ll_arr[:,0]==key)&(yx_p_ll_arr[:,2]==i)][:,3][0][features[i]]
                
        print('测试数据:',features,'各分类概率:',res2,',预测结果为:',max(res2,key=res2.get))
        
        
    

    数据来源自《统计学习方法》李航,表4.1,复制以下数据另存为naivebayes_data.csv文件即可。

    x1,x2,Y
    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
    

    参考资料:
    1、Machine-Learning-With-Python
    2、《机器学习实战》Peter Harrington著
    3、《机器学习》西瓜书,周志华著
    4、 斯坦福大学公开课 :机器学习课程
    5、机器学习视频,邹博
    6、[吴恩达_UFLDL中文教程]
    7、朴素贝叶斯算法–python实现
    8、《统计学习方法》李航

  • 相关阅读:
    如何做竞品分析报告
    软件架构入门
    系统内部矛盾的解决思路
    分表分库一
    Hbase随笔2
    Hbase随笔
    vertica在电信的应用
    理解RESTful架构
    百分点刘译璟
    数据产品的简介
  • 原文地址:https://www.cnblogs.com/hanzi5/p/10105618.html
Copyright © 2020-2023  润新知