vlambda博客
学习文章列表

正态贝叶斯分类器的python算法实现

今天写一篇正态贝叶斯分类器的python实现过程。


测试样本选用R的数据集IRIS


import numpy as np

import statsmodels.apiassm

import sympy
import math



iris = sm . datasets . get_rdataset ( 'iris' ). data #下载iris数据


这个数据的格式是DataFrame。后面在使用过程中,需要iris.values 格式转化为ndarray。


下面第一步,分类


该数据集没有现成的数值分类数据,通过下面的简单的pandas 数据处理下,得到数据集的三个数值分类



def replace ( x ):

    if x == 'setosa' :

        y = 0

    elif   x == 'virginica' :

        y = 2

    else :

        y = 1

    return   y


iris .loc[:, 'Species' ]= iris .loc[:, 'Species' ].apply( replace )


再定义一个分类函数。该数据集是150行,5列的数据结构,在最后分类,转化为50*4的数据结构。


def separate_by_class ( dataset ):

    separated = dict ()

    for i in range ( len ( dataset )):

        vector = dataset [ i ]

        class_value = vector [- 1 ]
       
        if class_value notin separated :

            separated [ class_value ] = list ()        
       
        separated [ class_value ].append( vector [ 0 : 4 ])
       
    return separated


每一类测试样本,有四个维度的测试数据,那么均值向量是一个1*4的数据结构。协方差矩阵的形状是4*4。下面我们需要计算均值向量。


第二步,我们需要定义均值函数,再通过字典的循环来计算不同类的均值向量。

def mean ( numbers ):

    return sum ( numbers )/ float ( len ( numbers ))



def   meanvector ( dataset ):    

    mean_list =[ mean ( column ) for column in zip (* dataset ) ]

    Len_list = [ len ( column ) for column in zip (* dataset ) ]

    return   mean_list , Len_list


第三步,我们需要计算协方差矩阵


在计算之前我们需要现将分类字典数据稍微变换下,这样在后面循环计算的时候方便快捷。这里和朴素贝叶斯分类器不同的是方差计算。


这里计算是采用的是样本矩估计。

def re_separated ( dataset ):
   
    separated = separate_by_class ( dataset )
   
    for k , v in separated . items ():
       
        mean_list , Len_list = meanvector ( separated [ k ])
       
        separated [ k ]= ( v , mean_list , Len_list [ 0 ])

    return   separated
   

def covMatrix ( separated ):

    cov = dict ()

    for class_value , rows in separated .items():    

        cov[class_value] = 1/(rows[2]-1)* \\

np.dot((rows[0]-np.array(rows[1])).T,(rows[0]-np.array(rows[1])))

   
    return   cov


在假设总体分布为正态分布的前提下,极大似然估计值计算和样本矩估计略有不同。主要体现在协方差计算中自由度。


第四步,对协方差矩阵进行特征值分解求协方差矩阵的逆,并计算协方差矩阵的行列式。


def   eig ( cov ):

    eig_dict = dict ()

    for   k , v in cov .items():

        e_vals , e_vecs = np . linalg . eig ( v )
       
        eig_dict [ k ]=( e_vals , e_vecs )
   
    return   eig_dict


这里进行特征值分解,有些用奇异值分解,但实际上,对于协方差矩阵来说,是实对称矩阵,行列数相同,用特征值分解更为适合。


这里分解出来的特征值需要通过np.diag,再和分解出来的特征向量矩阵相乘,就能还原分解前的矩阵。


np.matrix(e_vecs)*np.diag(e_vals)*\\

np.linalg.inv(np.matrix(e_vecs))


协方差矩阵的行列式和逆。


def   eig ( cov ):

    eig_dict = dict ()

    for   k , v in cov .items():

        e_vals , e_vecs = np . linalg . eig ( v )

        detcov = np . linalg . det ( v )

        invcov = np.matrix(e_vecs)*\\

np.linalg.inv(np.diag(e_vals))*\\

np.linalg.inv(np.matrix(e_vecs))

       
        eig_dict [ k ]=( e_vals , e_vecs , detcov , invcov )

    return   eig_dict


第五步,进行预测

根据估计出来的均值和协方差计算上式,最小值为最适合的分类类型。


row 为待预测分类的向量数据,输入后即可得到最佳的分类结果。


def   calculate_class_probabilities ( separated , eig_dict , row ):

    arg_dict = dict ()    

    for   k , v in eig_dict .items():
   
        arg = math . log ( v [ 2 ])+( row - separated [ k ][ 1 ]).T* v [ 3 ]*( row - separated [ k ][ 1 ])
       
        arg_dict [ k ] = arg
   
    return arg_dict


def predict ( arg_dict ):  

    best_label , best_prob = None , - 1

    for class_value , arg in arg_dict .items():

        if best_label isNoneor arg < best_prob :   #最小值

            best_prob = arg

            best_label = class_value

    return best_label


以上为正态贝叶斯分类器的python 代码实现。


代码实现仅为一个向量,重点在理解其中的计算过程,每一步计算和代码实现,才能实现设计和实现中的如火纯青。当然也可以直接使用现成的sklearn库。


贝叶斯概率计算原理,就不在本篇中叙述,相关知识可以搜索获得。


精算建模中使用机器学习的算法也会随着发展而不断扩大。金融、保险领域的机器学习也是我们需要不断学习和积累的技能。




End



独立专业中立的产品评测

多年数据挖掘与建模经验

,工作跨大数据、营销、风控、运营多个领域

擅长诊断各类业务问题

结合企业全面风险管理和精算数据科学

为企业构建和完善企业风险预警指标体系

协助企业更好实现战略目标及业务绩效目标


培训 | 咨询 | 分析 | 建模



分享 收藏 点赞 在看