朴素贝叶斯分类算法

贝叶斯定理

问题背景

当知道事件 B B B 发生的情况下事件 A A A 发生的概率 P ( A ∣ B ) P(A \mid B) P(AB) ,如何求 P ( B ∣ A ) P(B \mid A) P(BA)

根据条件概率公式可以得到:
P ( B ∣ A ) = P ( A B ) P ( A ) (1a) P(B \mid A)=\frac{P(AB)}{P(A)} \tag{1a} P(BA)=P(A)P(AB)(1a)
P ( A B ) = P ( B ∣ A ) × P ( A ) (1b) P(AB)=P(B \mid A) \times P(A) \tag{1b} P(AB)=P(BA)×P(A)(1b)
同理:
P ( A ∣ B ) = P ( A B ) P ( B ) (2a) P(A \mid B)=\frac{P(AB)}{P(B)} \tag{2a} P(AB)=P(B)P(AB)(2a)
P ( A B ) = P ( A ∣ B ) × P ( B ) (1b) P(AB)=P(A \mid B) \times P(B) \tag{1b} P(AB)=P(AB)×P(B)(1b)
联立得贝叶斯定理公式:
P ( B ∣ A ) = P ( A B ) P ( A ) = P ( A ∣ B ) × P ( B ) P ( A ) (3) P(B \mid A)=\frac{P(AB)}{P(A)}=\frac{P(A \mid B) \times P(B)}{P(A)} \tag{3} P(BA)=P(A)P(AB)=P(A)P(AB)×P(B)(3)
请添加图片描述
这里的 P ( A ) , P ( B ) P(A),P(B) P(A),P(B)都是依据原有数据集可知的,称为先验概率;而 P ( B ∣ A ) P(B|A) P(BA)是通过贝叶斯定理求出来的,称为后验概率

在机器学习的背景下,调整贝叶斯公式如下:
P ( 类别 ∣ 特征 ) = P ( 特征 ∣ 类别 ) × P ( 类别 ) P ( 特征 ) (4) P(\text{类别} \mid \text{特征})=\frac{P(\text{特征} \mid \text{类别}) \times P(\text{类别})}{P(\text{特征})} \tag{4} P(类别特征)=P(特征)P(特征类别)×P(类别)(4)
公式 ( 4 ) (4) (4) 利用先验概率,即特征和类别的概率;再利用不同类别中各个特征的概率分布,最后计算得到后验概率,即各个特征分布下的预测不同的类别。

朴素贝叶斯

朴素贝叶斯中的「朴素」,即条件独立,表示其假设预测的各个属性都是相互独立的,每个属性独立地对分类结果产生影响,条件独立在数学上的表示为: P ( A B ) = P ( A ) × P ( B ) P(AB)=P(A) \times P(B) P(AB)=P(A)×P(B)

显然,不同类别之间不一定是完全独立的关系,朴素贝叶斯算法是简化后的算法,但会牺牲一定的分类准确率。

朴素贝叶斯分类算法原理

P ( 类别 ∣ 特征 ) = P ( 特征 ∣ 类别 ) × P ( 类别 ) P ( 特征 ) (4) P(\text{类别} \mid \text{特征})=\frac{P(\text{特征} \mid \text{类别}) \times P(\text{类别})}{P(\text{特征})} \tag{4} P(类别特征)=P(特征)P(特征类别)×P(类别)(4)
公式 ( 4 ) (4) (4) 利用先验概率,即特征和类别的概率;再利用不同类别中各个特征的概率分布,最后计算得到后验概率,即各个特征分布下的预测不同的类别。

对于每个特征,其预测的不同类别中概率最高的就是这个特征的分类的类别,达到分类的目的。对于每种特征来说, P ( 特征 ) P(\text{特征}) P(特征)都是一样的,只需要比较 P ( 特征 ∣ 类别 ) × P ( 类别 ) P(\text{特征} \mid \text{类别}) \times P(\text{类别}) P(特征类别)×P(类别)大小即可。

朴素贝叶斯分类算法步骤

  • 第 1 步:设 X = { a 1 , a 2 , a 3 , … , a n } X = \left \{ a_{1},a_{2},a_{3},…,a_{n} \right \} X={a1,a2,a3,,an} 为预测数据,其中 a i a_{i} ai 是预测数据的特征值。

  • 第 2 步:设 Y = { y 1 , y 2 , y 3 , … , y m } Y = \left \{y_{1},y_{2},y_{3},…,y_{m} \right \} Y={y1,y2,y3,,ym} 为类别集合。

  • 第 3 步:计算 P ( y 1 ∣ x ) P(y_{1}\mid x) P(y1x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3x) , … … , P ( y m ∣ x ) P(y_{m}\mid x) P(ymx)

  • 第 4 步:寻找 P ( y 1 ∣ x ) P(y_{1}\mid x) P(y1x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3x) , … … , P ( y m ∣ x ) P(y_{m}\mid x) P(ymx) 中最大的概率 P ( y k ∣ x ) P(y_{k}\mid x) P(ykx) ,则 x x x 属于类别 y k y_{k} yk

给定示例数据

import pandas as pd

def create_data():
    # 生成示例数据
    data = {"x": ['r', 'g', 'r', 'b', 'g', 'g', 'r', 'r', 'b', 'g', 'g', 'r', 'b', 'b', 'g'],
            "y": ['m', 's', 'l', 's', 'm', 's', 'm', 's', 'm', 'l', 'l', 's', 'm', 'm', 'l'],
            "labels": ['A', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', 'B', 'B', 'B']}
    data = pd.DataFrame(data, columns=["labels", "x", "y"])
    return data

data = create_data()

极大似然估计

如何求 P ( 特征 ∣ 类别 ) × P ( 类别 ) P(\text{特征} \mid \text{类别}) \times P(\text{类别}) P(特征类别)×P(类别)

如何求 P ( 类别 ) P(\text{类别}) P(类别)

P ( y i = c k ) = ∑ i = 1 N I ( y i = c k ) N , k = 1 , 2 , 3 , … , m (5) P(y_{i}=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})}{N},k=1,2,3,…,m \tag{5} P(yi=ck)=Ni=1NI(yi=ck),k=1,2,3,,m(5)
这个很好理解,就是每种类别 y i y_i yi的数量 I I I占总样本 N N N的比值。

# 先验概率求解
def get_P_labels(labels):
    # P(\text{类别}) 先验概率计算
    labels = list(labels)  # 转换为 list 类型
    P_label = {}  # 设置空字典用于存入 label 的概率
    label_name=list(set(labels))
    for label in label_name:
        P_label[label] = labels.count(
            label) / float(len(labels))  # p = count(y) / count(Y)
    return P_label

P_labels = get_P_labels(data["labels"])
# {'A': 0.5333333333333333, 'B': 0.4666666666666667}
如何求 P ( 特征 ∣ 类别 ) P(\text{特征} \mid \text{类别}) P(特征类别)

首先我们将特征按序号合并生成一个 NumPy 数组。

import numpy as np
train_data = np.array(data.drop("labels",axis=1))
'''
array([['r', 'm'],
       ['g', 's'],
       ['r', 'l'],
       ['b', 's'],
       ['g', 'm'],
       ['g', 's'],
       ['r', 'm'],
       ['r', 's'],
       ['b', 'm'],
       ['g', 'l'],
       ['g', 'l'],
       ['r', 's'],
       ['b', 'm'],
       ['b', 'm'],
       ['g', 'l']], dtype=object)
'''

得到每一个类别的索引:

labels = data["labels"]
label_index = []
for y in P_labels.keys():
    temp_index = []
    # enumerate 函数返回 Series 类型数的索引和值,其中 i 为索引,label 为值
    for i, label in enumerate(labels):
        if (label == y):
            temp_index.append(i)
        else:
            pass
    label_index.append(temp_index)
# [[0, 1, 2, 3, 4, 5, 6, 7], [8, 9, 10, 11, 12, 13, 14]]

得到 A A A B B B 的索引,其中是 A A A 类别为前 8 8 8 条数据, B B B 类别为后 7 7 7 条数据。
在得到类别的索引之后,接下来就是找到我们需要的特征的索引, 以 A A A 类别中 r r r特征 为例。

r_index = [i for i, feature in enumerate(
    train_data[:, 0]) if feature == 'r']  # 效果等同于求类别索引中 for 循环
# [0, 2, 6, 7, 11]

计算出 P ( r ∣ A ) P(r|A) P(rA)

x_label = set(x_index) & set(label_index[0])
print('既符合 x = r 又是 A 类别的索引值:', x_label)
# 既符合 x = r 又是 A 类别的索引值: {0, 2, 6, 7}
x_label_count = len(x_label)
print('先验概率 P(r|A):', x_label_count / float(len(label_index[0])))
# 先验概率 P(r|A): 0.5

将上述流程转化为一个函数:

def get_P_fea_lab(P_label, features, data):
    # P(\text{特征}∣种类) 先验概率计算
    P_fea_lab = {}
    train_data = data.iloc[:, 1:]
    train_data = np.array(train_data)
    labels = data["labels"]
    for each_label in P_label.keys():
        label_index = [i for i, label in enumerate(
            labels) if label == each_label]  # labels 中出现 y 值的所有数值的下标索引
        # features[0] 在 trainData[:,0] 中出现的值的所有下标索引
        for j in range(len(features)):
            feature_index = [i for i, feature in enumerate(
                train_data[:, j]) if feature == features[j]]
            # set(x_index)&set(y_index) 列出两个表相同的元素
            fea_lab_count = len(set(feature_index) & set(label_index))
            key = str(features[j]) + '|' + str(each_label)
            P_fea_lab[key] = fea_lab_count / float(len(label_index))
    return P_fea_lab


features = ['r', 'm']
get_P_fea_lab(P_labels, features, data)
'''
{'r|A': 0.5,
 'm|A': 0.375,
 'r|B': 0.14285714285714285,
 'm|B': 0.42857142857142855}
'''

可以得到当特征 x x x y y y 的值为 r r r m m m 时,在不同类别下的先验概率。

完整代码
def classify(data, features):
    # 朴素贝叶斯分类器
    # 求 labels 中每个 label 的先验概率
    labels = data['labels']
    P_label = get_P_labels(labels)
    P_fea_lab = get_P_fea_lab(P_label, features, data)

    P = {}
    P_show = {}  # 后验概率
    for each_label in P_label:
        P[each_label] = P_label[each_label]
        for each_feature in features:
            key = str(each_label)+'|'+str(features)
            P_show[key] = P[each_label] * \
                P_fea_lab[str(each_feature) + '|' + str(each_label)]
            P[each_label] = P[each_label] * \
                P_fea_lab[str(each_feature) + '|' +
                          str(each_label)]  # 由于分母相同,只需要比较分子
    print(P_show)
    features_label = max(P, key=P.get)  # 概率最大值对应的类别
    return features_label
classify(data, ['r', 'm'])
# {"A|['r', 'm']": 0.1, "B|['r', 'm']": 0.02857142857142857}
# 这里类别A的概率大于B,故[r,m]特征分为A类别

贝叶斯估计

在做极大似然估计时,若类别中缺少一些特征,则就会出现概率值为 0 的情况。此时,就会影响后验概率的计算结果,使得分类产生偏差。于是引入贝叶斯估计。

贝叶斯估计的数学表达式为:
P ( y i = c k ) = ∑ i = 1 N I ( y i = c k ) + λ N + k λ (6) P(y_{i}=c_{k})=\frac{\sum_{i=1}^{N}I(y_{i}=c_{k})+\lambda }{N+k\lambda} \tag{6} P(yi=ck)=N+i=1NI(yi=ck)+λ(6)

其中 λ ≥ 0 \lambda \geq 0 λ0 等价于在随机变量各个取值的频数上赋予一个正数,当 λ = 0 \lambda=0 λ=0 时就是极大似然估计。在平时常取 λ = 1 \lambda=1 λ=1,这时称为拉普拉斯平滑。 k k k取值为类别数目。

朴素贝叶斯的三种常见模型

多项式模型

上述过程就是多项式模型,特征离散,参数估计方法采用贝叶斯估计。

伯努利模型

伯努利模型中每个特征的取值只能是 1 和 0。

高斯模型

处理连续的特征变量,采用高斯模型。高斯模型是假设连续变量的特征数据是服从高斯分布的,高斯分布函数表达式为:
P ( x i ∣ y k ) = 1 2 π σ y k , i e x p ( − ( x − μ y k , i ) 2 2 σ y k 2 , i ) P(x_{i}|y_{k})=\frac{1}{\sqrt{2\pi}\sigma_{y_{k},i}}exp(-\frac{(x-\mu_{y_{k},i}) ^{2}}{2\sigma ^{2}_{y_{k}},i}) P(xiyk)=2π σyk,i1exp(2σyk2,i(xμyk,i)2)

  • μ y k , i \mu_{y_{k},i} μyk,i 表示类别为 y k y_{k} yk 的样本中,第 i i i 维特征的均值。
  • σ y k 2 , i \sigma ^{2}_{y_{k}},i σyk2,i 表示类别为 y k y_{k} yk 的样本中,第 i i i 维特征的方差。

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值