朴素贝叶斯分类算法

文章目录

贝叶斯定理

问题背景

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

根据条件概率公式可以得到:
P ( B ∣ A ) = P ( A B ) P ( A ) (1a) P(B \mid A)=\frac{P(AB)}{P(A)} \tag{1a} P(B∣A)=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(B∣A)×P(A)(1b)

同理:
P ( A ∣ B ) = P ( A B ) P ( B ) (2a) P(A \mid B)=\frac{P(AB)}{P(B)} \tag{2a} P(A∣B)=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(A∣B)×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(B∣A)=P(A)P(AB)=P(A)P(A∣B)×P(B)(3)

这里的 P ( A ) , P ( B ) P(A),P(B) P(A),P(B)都是依据原有数据集可知的,称为先验概率 ;而 P ( B ∣ A ) P(B|A) P(B∣A)是通过贝叶斯定理求出来的,称为后验概率

在机器学习的背景下,调整贝叶斯公式如下:
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(y1∣x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2∣x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3∣x) , ... ... ..., P ( y m ∣ x ) P(y_{m}\mid x) P(ym∣x) 。

  • 第 4 步:寻找 P ( y 1 ∣ x ) P(y_{1}\mid x) P(y1∣x) , P ( y 2 ∣ x ) P(y_{2}\mid x) P(y2∣x) , P ( y 3 ∣ x ) P(y_{3}\mid x) P(y3∣x) , ... ... ..., P ( y m ∣ x ) P(y_{m}\mid x) P(ym∣x) 中最大的概率 P ( y k ∣ x ) P(y_{k}\mid x) P(yk∣x) ,则 x x x 属于类别 y k y_{k} yk。

给定示例数据

python 复制代码
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)=N∑i=1NI(yi=ck),k=1,2,3,...,m(5)

这个很好理解,就是每种类别 y i y_i yi的数量 I I I占总样本 N N N的比值。

python 复制代码
# 先验概率求解
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 数组。

python 复制代码
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)
'''

得到每一个类别的索引:

python 复制代码
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特征 为例。

python 复制代码
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(r∣A) 。

python 复制代码
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

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

python 复制代码
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 时,在不同类别下的先验概率。

完整代码
python 复制代码
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+kλ∑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(xi∣yk)=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 维特征的方差。
相关推荐
zhangbin_2372 小时前
【Python机器学习】循环神经网络(RNN)——利用Keras实现循环神经网络
python·rnn·深度学习·神经网络·机器学习·自然语言处理·keras
日暮途远z2 小时前
李沐pytorch 课程 深度学习D2l python3.12安装方法
人工智能·pytorch·深度学习
白色机械键盘4 小时前
模型部署基础
人工智能
强哥带你学BP神经网络4 小时前
基于GA-BP遗传算法优化神经网络的多输入多输出数据预测-Python代码实现
人工智能·python·深度学习·神经网络·机器学习
成都古河云4 小时前
智慧体育场馆:科技引领未来运动体验
大数据·网络·人工智能·科技·物联网·运维开发
ZStack开发者社区4 小时前
云轴科技ZStack 获鲲鹏应用创新大赛2024上海赛区决赛一等奖
大数据·人工智能·科技
y_dd5 小时前
【mechine learning-九-梯度下降】
人工智能·机器学习
qq_550337995 小时前
研1日记12
人工智能·算法·机器学习
AI进修生5 小时前
CancerLLM: 癌症领域的大型语言模型
人工智能·语言模型·自然语言处理