Bootstrap

Naive Bayes(朴素贝叶斯分类器)

朴素贝叶斯分类器

引言

概率模型的训练过程就是对参数进行估计。对于参数估计,分为两个学派:频率学派贝叶斯学派
频率学派认为参数的真值是固定的、未知的一个常数,观察到的数据是随机的。他们主要关注的是样本空间,提出的解决方法是最大似然估计(例如logistic regression)。

贝叶斯学派认为参数的真值是未观察到的随机变量,但是随机变量本身也可以有分布,观察到的数据是固定的。他们主要关注点是参数空间,重视参数的分布。通过参数的先验(prior)估计后验概率。提出的解决方法是最大后验估计。

频率学派的观点是对总体分布做适当的假定,结合样本信息对参数进行统计推断,涉及总体信息和样本信息,贝叶斯学派认为除了上述两类信息,统计推断应该引入先验信息。
朴素贝叶斯的分类原理是利用贝叶斯公式,根据特征的先验概率计算后验概率,选择具有最大后验概率的类别作为该特征所属的类别。

通过贝叶斯公式可以明过去,知未来。

原理

贝叶斯公式为:
P ( B ∣ A ) = P ( A ∣ B ) P ( B ) P ( A ) P(B|A) = \frac{P(A|B)P(B)}{P(A)} P(BA)=P(A)P(AB)P(B)
换个中文形式可以写为
P ( 类别 ∣ 特征 ) = p ( 特征 ∣ 类别 ) p ( 类别 ) p ( 特征 ) P(类别|特征) =\frac {p(特征|类别)p(类别)}{p(特征)} P(类别特征)=p(特征)p(特征类别)p(类别)
我们假设待分类样本S为:

特征集合 X = { x 1 , x 2 , . . . , x n } X = \{x_1,x_2,...,x_n\} X={x1,x2,...,xn}
类别标签集合 C = { c 1 , c 2 , . . . , c m } C = \{c_1,c_2,...,c_m\} C={c1,c2,...,cm}
表示样本S具有n个特征,会有m种不同的分类结果。
那么,此时贝叶斯公式可以写为
P ( c i ∣ X ) = p ( X , c i ) P ( X ) = P ( X ∣ c i ) P ( c i ) P ( X ) P(c_i|X) = \frac{p(X,c_i)}{P(X)} = \frac{P(X|c_i)P(c_i)}{P(X)} P(ciX)=P(X)p(X,ci)=P(X)P(Xci)P(ci)

其中 P ( X ∣ c i ) P ( X ) \frac{P(X|c_i)}{P(X)} P(X)P(Xci)可以视作 调整因子,使预测概率更加接近真实概率

因而,贝叶斯公式可以调整为:后验概率 = 先验概率 * 调整因子
当调整因子大于1时,先验概率被增强,事件 c i c_i ci发生的可能性变大。
当调整因子等于1时,数据X对判断事件 c i c_i ci发生的概率没有帮助。
当调整因子小于1时,先验概率被削弱,事件 c i c_i ci发生的可能性变小。

朴素贝叶斯的朴素之处在于,我们假设每个特征之间都是相互独立的。
那么有:
P ( X ∣ c i ) = P ( { x 1 , x 2 , . . . , x n } ∣ c i ) = ∏ j = 1 n P ( x j ∣ c i ) P(X|c_i) = P(\{x_1,x_2,...,x_n\}|c_i) = \prod_{j=1}^nP(x_j|c_i) P(Xci)=P({x1,x2,...,xn}ci)=j=1nP(xjci)

其中,n表示特征数目, x j x_j xj表示在第j个特征上的取值。

对于所有类别来说,P(X) 相同,因此,朴素贝叶斯公式为:
c i = a r g m a x c i ∈ C P ( c i ∣ X ) = a r g m a x c i ∈ C P ( c i ) ∏ j = 1 n P ( x j ∣ c i ) c_i = argmax_{c_i \in C}P(c_i|X) = argmax_{c_i \in C}P(c_i)\prod_{j=1}^{n}P(x_j|c_i) ci=argmaxciCP(ciX)=argmaxciCP(ci)j=1nP(xjci)
那么,根据训练集D就需要求出:

  1. 先验概率 P ( c ) P(c) P(c)
  2. 每个特征 x i x_i xi的条件概率 P ( x i ∣ c ) P(x_i|c) P(xic)
    P ( c ) = ∣ D c ∣ ∣ D ∣ P(c) = \frac{|D_c|}{|D|} P(c)=DDc

D c D_c Dc表示训练集中第c类样本组成的集合。

对于离散属性: P ( x i ∣ c ) = ∣ D c , x i ∣ D c P(x_i|c) = \frac{|D_{c,xi}|}{D_c} P(xic)=DcDc,xi

D c , x i D_{c,x_i} Dc,xi表示 D c D_c Dc在第i个属性上取值为 x i x_i xi的样本组成的集合。

对于连续属性: p ( x i ∣ c ) = 1 2 π σ c , i e ( − ( x i − μ c , i ) 2 2 σ c , i 2 ) p(x_i|c) = \frac{1}{\sqrt{2 \pi } \sigma_{c,i} } e^{(-\frac{(x_i - \mu_{c,i})^2}{2\sigma_{c,i}^2})} p(xic)=2π σc,i1e(2σc,i2(xiμc,i)2)

假定 p ( x i ∣ c ) ∼ N ( μ c , i , σ c , i 2 ) p(x_i|c) \sim N(\mu_{c,i},\sigma_{c,i}^2) p(xic)N(μc,i,σc,i2)
μ c , i \mu_{c,i} μc,i σ c , i 2 \sigma_{c,i}^2 σc,i2是第c类样本在第i个属性上取值的均值和方差。

朴素贝叶斯的三种分类器:

  • 高斯分类器:样本特征分布是连续值,服从正态分布。
  • 伯努利分类器:样本特征的分布是二元离散值。
  • 多项式分类器:样本特征值的分布是多元离散值。

代码

import numpy as np
import math
import pandas as  pd

dataSet = pd.read_csv('./data/西瓜数据集3.0.txt').iloc[:,1:]
dataSet = np.array(dataSet)
labels = ['色泽', '根蒂', '敲声', '纹理', '脐部', '触感', '密度','含糖率']
testSet = ['青绿', '蜷缩', '浊响', '清晰', '凹陷', '硬滑', 0.697, 0.460]


#计算均值、标准差
def mean_std(feature,cla):
    lst = [item[labels.index(feature)] for item in dataSet if item[-1] == cla]
    mean = round(np.mean(lst),3)#均值
    std = round(np.mean(lst),3)#标准差

    return mean,std

#计算先验
def prior():
    countG = 0 #好瓜数量
    countB = 0 #坏瓜数量
    countAll = len(dataSet) #总数
    
    for item in dataSet :
        if item[-1] == '是':
            countG +=1
        if item[-1] == '否':
            countB +=1
    
    P_G = round(countG/countAll,3)
    P_B = round(countB/countAll,3)
    
    return P_G,P_B

#计算条件概率p(xi|c)


def P(index, cla):
    countG = 0  # 初始化好瓜数量
    countB = 0  # 初始化坏瓜数量
    for item in dataSet:    # 统计好瓜个数
        if item[-1] == "是":
            countG += 1
        if item[-1] == "否":
            countB += 1
            
    lst = [item for item in dataSet if (item[-1] == cla) & (item[index] == testSet[index])] # lst为cla类中第index个属性上取值为xi的样本组成的集合
    P = round(len(lst)/(countG if cla=="是" else countB), 3)  # 计算条件概率
    
    
    return P

#  计算连续属性的条件概率p(xi|c)
def p():
    denG_mean, denG_std = mean_std("密度", "是")      # 好瓜密度的均值、标准差
    denB_mean, denB_std = mean_std("密度", "否")      # 坏瓜密度的均值、标准差
    sugG_mean, sugG_std = mean_std("含糖率", "是")    # 好瓜含糖率的均值、标准差
    sugB_mean, sugB_std = mean_std("含糖率", "否")    # 坏瓜含糖率的均值、标准差
    # p(密度|好瓜)
    p_density_G = (1/(math.sqrt(2*math.pi)*denG_std))*np.exp(-(((testSet[labels.index("密度")]-denG_mean)**2)/(2*(denG_std**2))))
    p_density_G = round(p_density_G, 3)
    # p(密度|坏瓜)
    p_density_B = (1/(math.sqrt(2*math.pi)*denB_std))*np.exp(-(((testSet[labels.index("密度")]-denB_mean)**2)/(2*(denB_std**2))))
    p_density_B = round(p_density_B, 3)
    # p(含糖率|好瓜)
    p_sugar_G = (1/(math.sqrt(2*math.pi)*sugG_std))*np.exp(-(((testSet[labels.index("含糖率")]-sugG_mean)**2)/(2*(sugG_std**2))))
    p_sugar_G = round(p_sugar_G, 3)
    # p(含糖率|坏瓜)
    p_sugar_B = (1/(math.sqrt(2*math.pi)*sugB_std))*np.exp(-(((testSet[labels.index("含糖率")]-sugB_mean)**2)/(2*(sugB_std**2))))
    p_sugar_B = round(p_sugar_B, 3)
 
    return p_density_G, p_density_B, p_sugar_G, p_sugar_B

# 后验概率P(c|xi)
def bayes():
    # 计算类先验概率
    P_G, P_B = prior()
    # 计算离散属性的条件概率
    P0_G = P(0, "是") # P(青绿|好瓜)
    P0_B = P(0, "否") # P(青绿|坏瓜)
    P1_G = P(1, "是") # P(蜷缩|好瓜)
    P1_B = P(1, "否") # P(蜷缩|好瓜)
    P2_G = P(2, "是") # P(浊响|好瓜)
    P2_B = P(2, "否") # P(浊响|好瓜)
    P3_G = P(3, "是") # P(清晰|好瓜)
    P3_B = P(3, "否") # P(清晰|好瓜)
    P4_G = P(4, "是") # P(凹陷|好瓜)
    P4_B = P(4, "否") # P(凹陷|好瓜)
    P5_G = P(5, "是") # P(硬滑|好瓜)
    P5_B = P(5, "否") # P(硬滑|好瓜)
    #  计算连续属性的条件概率
    p_density_G, p_density_B, p_sugar_G, p_sugar_B = p()
 
    #  计算后验概率
    isGood = P_G * P0_G * P1_G * P2_G * P3_G * P4_G * P5_G * p_density_G * p_sugar_G    # 计算是好瓜的后验概率
    isBad = P_B * P0_B * P1_B * P2_B * P3_B * P4_B * P5_B * p_density_B * p_sugar_B     # 计算是坏瓜的后验概率
 
    return isGood,isBad

if __name__=='__main__':
    
    testSet1=[testSet]#用于打印数据
    df = pd.DataFrame(testSet1, columns=labels, index=[1])
    print("=======================待测样本========================")
    print(f"待测集:\n{df}")
 
    isGood, isBad = bayes()
    print("=======================后验概率========================")
    print("后验概率:")
    print(f"P(好瓜|xi) = {isGood}")
    print(f"P(好瓜|xi) = {isBad}")
    print("=======================预测结果========================")
    print("predict ---> 好瓜" if (isGood > isBad) else "predict ---> 坏瓜")

======================= 待测样本 ========================
待测集:
色泽 根蒂 敲声 纹理 脐部 触感 密度 含糖率
1 青绿 蜷缩 浊响 清晰 凹陷 硬滑 0.697 0.46
======================= 后验概率========================
后验概率:
P(好瓜|xi) = 0.02672366381034852
P(好瓜|xi) = 0.0002283913232490495
======================= 预测结果========================
predict —> 好瓜

#西瓜数据集3.0
编号,色泽,根蒂,敲声,纹理,脐部,触感,密度,含糖率,好瓜
0,青绿,蜷缩,浊响,清晰,凹陷,硬滑,0.697,0.460,1,乌黑,蜷缩,沉闷,清晰,凹陷,硬滑,0.774,0.376,2,乌黑,蜷缩,浊响,清晰,凹陷,硬滑,0.634,0.264,3,青绿,蜷缩,沉闷,清晰,凹陷,硬滑,0.608,0.318,4,浅白,蜷缩,浊响,清晰,凹陷,硬滑,0.556,0.215,5,青绿,稍蜷,浊响,清晰,稍凹,软粘,0.403,0.237,6,乌黑,稍蜷,浊响,稍糊,稍凹,软粘,0.481,0.149,7,乌黑,稍蜷,浊响,清晰,稍凹,硬滑,0.437,0.211,8,乌黑,稍蜷,沉闷,稍糊,稍凹,硬滑,0.666,0.091,9,青绿,硬挺,清脆,清晰,平坦,软粘,0.243,0.267,10,浅白,硬挺,清脆,模糊,平坦,硬滑,0.245,0.057,11,浅白,蜷缩,浊响,模糊,平坦,软粘,0.343,0.099,12,青绿,稍蜷,浊响,稍糊,凹陷,硬滑,0.639,0.161,13,浅白,稍蜷,沉闷,稍糊,凹陷,硬滑,0.657,0.198,14,乌黑,稍蜷,浊响,清晰,稍凹,软粘,0.360,0.370,15,浅白,蜷缩,浊响,模糊,平坦,硬滑,0.042,0.042,16,青绿,蜷缩,沉闷,稍糊,稍凹,硬滑,0.103,0.103,

参考

知乎
csdn博客
code

悦读

道可道,非常道;名可名,非常名。 无名,天地之始,有名,万物之母。 故常无欲,以观其妙,常有欲,以观其徼。 此两者,同出而异名,同谓之玄,玄之又玄,众妙之门。

;