1. 程式人生 > >拉普拉斯修正的樸素貝葉斯分類器及AODE分類器

拉普拉斯修正的樸素貝葉斯分類器及AODE分類器

下面的一些原理來著周志華老師的西瓜書。

***************************************************************************************************************

拉普拉斯修正的樸素貝葉斯分類器主要目的是為了避免遇到某些特徵屬性為空時,使得相關後驗概率為0的情況。其相關計算公式如下:


其中Dc表示訓練集中第c類樣本的集合,P(c)表示c類的先驗概率,N表示標籤的類別數;Dcxi表示第i個屬性上位屬性xi的集合,Ni表示第i個屬性的類別數。

判別函式如下(公式1):

AODE是一種基於整合學習機制、更為強大的獨依賴分類器,為半樸素貝葉斯分類器。其相關的計算公式如下:


通過以上的兩個關鍵函式12,判斷各個關鍵概率的大小來判斷類別。當連乘過小的時候,可採用開方或者取對數的方式。

使用的資料如下:
編號	色澤	根蒂	敲聲	紋理	臍部	觸感	密度	含糖量	好瓜
1	青綠	蜷縮	濁響	清晰	凹陷	硬滑	0.697	0.46	是
2	烏黑	蜷縮	沉悶	清晰	凹陷	硬滑	0.774	0.376	是
3	烏黑	蜷縮	濁響	清晰	凹陷	硬滑	0.634	0.264	是
4	青綠	蜷縮	沉悶	清晰	凹陷	硬滑	0.608	0.318	是
5	淺白	蜷縮	濁響	清晰	凹陷	硬滑	0.556	0.215	是
6	青綠	稍蜷	濁響	清晰	稍凹	軟粘	0.403	0.237	是
7	烏黑	稍蜷	濁響	稍糊	稍凹	軟粘	0.481	0.149	是
8	烏黑	稍蜷	濁響	清晰	稍凹	硬滑	0.437	0.211	是
9	烏黑	稍蜷	沉悶	稍糊	稍凹	硬滑	0.666	0.091	否
10	青綠	硬挺	清脆	清晰	平坦	軟粘	0.243	0.267	否
11	淺白	硬挺	清脆	模糊	平坦	硬滑	0.245	0.057	否
12	淺白	蜷縮	濁響	模糊	平坦	軟粘	0.343	0.099	否
13	青綠	稍蜷	濁響	稍糊	凹陷	硬滑	0.639	0.161	否
14	淺白	稍蜷	沉悶	稍糊	凹陷	硬滑	0.657	0.198	否
15	烏黑	稍蜷	濁響	清晰	稍凹	軟粘	0.36	0.37	否
16	淺白	蜷縮	濁響	模糊	平坦	硬滑	0.593	0.042	否
17	青綠	蜷縮	沉悶	稍糊	稍凹	硬滑	0.719	0.103	否
# -*- coding: utf-8 -*-
"""
Created on Wed Jan  4 21:05:48 2017

@author: ZQ
"""

import numpy as np
from math import pi as PI


def loadData(filename):
    file = open(filename)
    lines = file.readlines()
    data = []
    for line in lines[1:]:
        d = line.strip().split('\t')
        d = d[1:]
        data.append(d)
    return np.array(data)

#所有計算採用拉普拉斯修正,樸素貝葉斯分類   
#計算先驗概率
def calcpro(data):
    data_count = len(data)
    s_l = set(data[:,-1])
    N = len(s_l)
    yes_count = 0
    for vec in data:
        if vec[-1] == '是':
            yes_count += 1
    return (yes_count+1)/(data_count+N)

#用於計算標籤的條件概率
def calcLabelpro(data,i,value):
    data_yes_len = 0
    fec_yes = 0
    fec_no = 0
    s_f = set(data[:,i])
    Ni = len(s_f)
    for vec in data:
        if vec[-1] == '是':
            data_yes_len += 1
        if vec[i] == value:            
            if vec[-1] == '是':
                fec_yes += 1
            else:
                fec_no += 1
    #print(fec_yes,fec_no,data_yes_len)
    return (fec_yes+1)/(data_yes_len+Ni),(fec_no+1)/(len(data)-data_yes_len+Ni)

#高斯概率密度
def gass(x,u,d):
    pro = (2*PI)**0.5*d**0.5
    pro = 1/pro
    pro = pro*np.exp(-(x-u)**2/(2*d))
    return pro
#用於計算連續數值的概率密度
def calcNumpro(data,i,value):
    data_yes = []
    data_no = []
    for vec in data:
        if vec[-1] == '是':
            data_yes.append(vec[i])
        else:
            data_no.append(vec[i])
            
    num_yes = list(map(float,data_yes))
    num_no = list(map(float,data_no))
    num_yes = np.array(num_yes)
    num_no = np.array(num_no)
    #print(num_yes.mean(),num_yes.var()**0.5)
    #計算均值與方差
    mean_yes = num_yes.mean()
    var_yes = num_yes.var()
    mean_no = num_no.mean()
    var_no = num_no.var()
    
    pro_yes = gass(value,mean_yes,var_yes)
    pro_no = gass(value,mean_no,var_no)
    
    return pro_yes,pro_no

def Bayes(train_data,test_data):
    #獲得先驗概率
    pro_yes = calcpro(train_data)
    pro_no = 1 - pro_yes
    for i in range(len(test_data)-1):
        if i < 6:
           py,pn = calcLabelpro(data,i,test_data[i])
           pro_yes = pro_yes*py
           pro_no = pro_no*pn
        else:
            py,pn = calcNumpro(data,i,float(test_data[i]))
            pro_yes = pro_yes*py
            pro_no = pro_no*pn
    if pro_yes > pro_no:
        print('是')
    else:
        print('否')
    print(test_data[-1])
    
#AODE分類器,未實現連續屬性(使用每個屬性作為超父來構建SPODE)
#首先計算P(C,Xi)
def calcP_C_Xi(data,i,value):
    D = len(data)
    label_set = set(data[:,-1])
    N = len(label_set)
    i_set = set(data[:,i])
    Ni = len(i_set)
    Xi_yes_count = 0
    Xi_no_count = 0
    for vec in data:
        if vec[i] == value:
            if vec[-1] == '是':
                Xi_yes_count += 1
            else:
                Xi_no_count += 1
    P_y = (Xi_yes_count+1)/(D + N*Ni)
    P_n = (Xi_no_count+1)/(D + N*Ni)
    return P_y,P_n
#其次計算P(Xj|C,Xi)
def calcP_Xj_C_Xi(data,j,i,value_j,value):
    j_set = set(data[:,j])
    Nj = len(j_set)
    Xi_y_count = 0
    Xi_n_count = 0
    Xij_y_count = 0
    Xij_n_count = 0
    for vec in data:
        if vec[i] == value:
            if vec[-1] == '是':
                Xi_y_count += 1
            else:
                Xi_n_count += 1
            if vec[j] == value_j:
                if vec[-1] == '是':
                    Xij_y_count += 1
                else:
                    Xij_n_count += 1
    p_y = (Xij_y_count + 1)/(Xi_y_count + Nj)
    p_n = (Xij_n_count + 1)/(Xi_n_count + Nj)
    return p_y,p_n
def AODE(train_data,test_data):
    p_y_list = []
    p_n_list = []
    p_y = 1
    p_n = 1
    for i in range(6):
        P_c_Xi_y,P_c_Xi_n = calcP_C_Xi(data,i,test_data[i])
        for j in range(6):            
            P_c_Xji_y,P_c_Xji_n = calcP_Xj_C_Xi(data,j,i,test_data[j],test_data[i])
            p_y = p_y * P_c_Xji_y
            p_n = p_n * P_c_Xji_n
        p_y_list.append(p_y*P_c_Xi_y)
        p_n_list.append(p_n*P_c_Xi_n)
    if sum(p_y_list) > sum(p_n_list):
        print('是')
    else:
        print('否')
    print(test_data[-1])

if __name__ == '__main__':
    data = loadData('watermelon3.0.txt')
    test_data = data[3,:]
    Bayes(data,test_data)
    AODE(data,test_data)