天天看點

Python實作樸素貝葉斯分類器1.樸素貝葉斯概念2.樸素貝葉斯算法

1.樸素貝葉斯概念

在所有的機器學習分類算法中,樸素貝葉斯和其他絕大多數的分類算法都不同。對于大多數的分類算法,比如決策樹,KNN,邏輯回歸,支援向量機等,他們都是判别方法,也就是直接學習出特征輸出Y和特征X之間的關系,要麼是決策函數Y=f(X),要麼是條件分布P(Y|X)。但是樸素貝葉斯卻是生成方法,也就是直接找出特征輸出Y和特征X的聯合分布P(X,Y),然後用P(Y|X)=P(X,Y)/P(X)得出。

具體算法思想過程如下圖(《統計學習方法》李航,P50):

Python實作樸素貝葉斯分類器1.樸素貝葉斯概念2.樸素貝葉斯算法

2.樸素貝葉斯算法

根據以上公式算法,python實作樸素貝葉斯算法思想過程如下:

我們先計算 P ( Y = c k ) P(Y=c_k) P(Y=ck​)的機率,再計算每一個特征 P ( x ∣ y ) P(x|y) P(x∣y)的機率得到每一列x中的特征出現機率,最終形成y_p及yx_p機率矩陣,針對新資料查詢這兩個機率矩陣,得到每一種Y=c_k時的機率,機率最大的那個分類就是預測結果,需要注意的是: P ( c ∣ x ) = P ( c ) P ( x ∣ c ) / P ( x ) P(c|x)=P(c)P(x|c)/P(x) P(c∣x)=P(c)P(x∣c)/P(x),同一組資料,對所有分類來說分母 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
           

預測結果圖:

Python實作樸素貝葉斯分類器1.樸素貝葉斯概念2.樸素貝葉斯算法

所有代碼如下:

# -*- 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:\n',y_p)
    print('yx_p:\n',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('\n 2、樸素貝葉斯算法,貝葉斯估計')
    print('y_p_ll:\n',y_p_ll)
    print('yx_p_ll:\n',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、《統計學習方法》李航