其他分享
首页 > 其他分享> > 朴素贝叶斯与贝叶斯网络

朴素贝叶斯与贝叶斯网络

作者:互联网

1、朴素贝叶斯

朴素贝叶斯是一种基于贝叶斯定理和特征条件独立假设的分类算法。

简单而言,对于给定的训练数据,朴素贝叶斯先基于特征条件独立假设学习输入和输出的联合概率分布,然后基于此分布对于新的实例,利用贝叶斯定理计算出最大的后验概率。朴素贝叶斯不会直接学习输入输出的联合概率分布,而是通过学习类的先验概率类条件概率来完成。

贝叶斯公式

所谓朴素贝叶斯中朴素的含义,即特征条件独立假设,条件独立假设就是说用于分类的特征在类确定的条件下都是条件独立的。这一假设使得朴素贝叶斯的学习成为可能。朴素贝叶斯算法具体步骤如下。

首先计算类先验概率:

先验概率

类先验概率可直接用极大似然估计进行计算。

然后计算类条件概率:

条件概率

最后给定新的实例,计算其对应的最大后验概率,然后判断其所属的类别:

后验概率

以上就是朴素贝叶斯的基本原理。下面基于numpy和pandas来实现朴素贝叶斯算法。

导入package

import numpy as np
import pandas as pd

构造数据集

### 来自于李航统计学习方法表4.1
x1 = [1,1,1,1,1,2,2,2,2,2,3,3,3,3,3]
x2 = ['S','M','M','S','S','S','M','M','L','L','L','M','M','L','L']
y = [-1,-1,1,1,-1,-1,-1,1,1,1,1,1,1,1,-1]

df = pd.DataFrame({'x1':x1, 'x2':x2, 'y':y})
df.head()
x1 x2 y
0 1 S -1
1 1 M -1
2 1 M 1
3 1 S 1
4 1 S -1

取出特征和标签

X = df[['x1', 'x2']]
y = df[['y']]

定义朴素贝叶斯训练过程

def nb_fit(X, y):
    classes = y[y.columns[0]].unique()
    class_count = y[y.columns[0]].value_counts()
    class_prior = class_count/len(y)
    
    prior = dict()
    for col in X.columns:
        for j in classes:
            p_x_y = X[(y==j).values][col].value_counts()
            for i in p_x_y.index:
                prior[(col, i, j)] = p_x_y[i]/class_count[j]
    return classes, class_prior, prior

拟合示例如下

nb_fit(X, y)
(array([-1,  1], dtype=int64),
  1    0.6
 -1    0.4
 Name: y, dtype: float64,
 {('x1', 1, -1): 0.5,
  ('x1', 2, -1): 0.3333333333333333,
  ('x1', 3, -1): 0.16666666666666666,
  ('x1', 3, 1): 0.4444444444444444,
  ('x1', 2, 1): 0.3333333333333333,
  ('x1', 1, 1): 0.2222222222222222,
  ('x2', 'S', -1): 0.5,
  ('x2', 'M', -1): 0.3333333333333333,
  ('x2', 'L', -1): 0.16666666666666666,
  ('x2', 'M', 1): 0.4444444444444444,
  ('x2', 'L', 1): 0.4444444444444444,
  ('x2', 'S', 1): 0.1111111111111111})

最后定义预测函数

classes, class_prior, prior = nb_fit(X, y)

def predict(X_test):
    res = []
    for c in classes:
        p_y = class_prior[c]
        p_x_y = 1
        for i in X_test.items():
            p_x_y *= prior[tuple(list(i)+[c])]
        res.append(p_y*p_x_y)
    return classes[np.argmax(res)]

给定测试实例并进行预测

X_test = {'x1': 2, 'x2': 'S'}
classes, class_prior, prior = nb_fit(X, y)
print('测试数据预测类别为:', predict(X_test))

测试数据预测类别为: -1

image-20220507210604652

image-20220507210651141

sklearn实现

from sklearn.datasets import load_iris
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import GaussianNB
from sklearn.metrics import accuracy_score
X, y = load_iris(return_X_y=True)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5, random_state=0)
gnb = GaussianNB()
y_pred = gnb.fit(X_train, y_train).predict(X_test)
print("Accuracy of GaussianNB in iris data test:",accuracy_score(y_test, y_pred))

2、贝叶斯网络

2.1 引例

在上一讲中,我们讲到了经典的朴素贝叶斯算法。朴素贝叶斯的一大特点就是特征的条件独立假设,但在现实情况下,条件独立这个假设通常过于严格,在实际中很难成立。特征之间的相关性限制了朴素贝叶斯的性能, 所以本节将继续介绍一种放宽了条件独立假设的贝叶斯算法——贝叶斯网络(Bayesian Network)。

先以一个例子进行引入。假设我们需要通过头像真实性、粉丝数量和动态更新频率来判断一个微博账号是否为真实账号。各特征属性之间的关系如下图所示:
微博账号是否真实

上图是一个有向无环图(DAG),每个节点表示一个特征或者随机变量,特征之间的关系则是用箭头连线来表示,比如说动态的更新频率、粉丝数量和头像真实性都会对一个微博账号的真实性有影响,而头像真实性又对粉丝数量有一定影响。但仅有各特征之间的关系还不足以进行贝叶斯分析。除此之外,贝叶斯网络中每个节点还有一个与之对应的概率表。

假设账号是否真实和头像是否真实有如下概率表:

A = 0 A = 1
0.13 0.87
H = 0 H = 1
A = 0 0.88 0.12
A = 1 0.25 0.75

第一张概率表表示的是账号是否真实,因为该节点没有父节点,可以直接用先验概率来表示,表示账号真实与否的概率。(A = 0账号为真,A = 1账号为假)

第二张概率表表示的是账号真实性对于头像真实性的条件概率。比如说在头像为真实头像的条件下,账号为真的概率为0.88。(H = 0 头像为真,H = 1头像为假)在有了DAG和概率表之后,我们便可以利用贝叶斯公式进行定量的因果关系推断。假设我们已知某微博账号使用了虚假头像,那么其账号为虚假账号的概率可以推断为:

利用贝叶斯公式,我们可知在虚假头像的情况下其账号为虚假账号的概率为0.345。

2.2 贝叶斯网络性质

上面的例子可以让大家直观的感受到贝叶斯网络的作用。一个贝叶斯网络通常由有向无环图(DAG)和节点对应的概率表组成。其中DAG由节点(node)和有向边(edge)组成,节点表示特征属性或随机变量,有向边表示各变量之间的依赖关系。贝叶斯网络的一个重要性质是:当一个节点的父节点概率分布确定之后,该节点条件独立于其所有的非直接父节点。这个性质方便于我们计算变量之间的联合概率分布。

一般来说,多变量非独立随机变量的联合概率分布计算公式如下:

当有了上述性质之后,该式子就可以简化为:

基于先验概率、条件概率分布和贝叶斯公式,我们便可以基于贝叶斯网络进行概率推断。

2.3 基于pgmpy的贝叶斯网络实现

本节我们基于pgmpy来构造贝叶斯网络和进行建模训练。pgmpy是一款基于Python的概率图模型包,主要包括贝叶斯网络和马尔可夫蒙特卡洛等常见概率图模型的实现以及推断方法。本节使用pgmpy包来实现简单的贝叶斯网络。

我们以学生获得推荐信质量这样一个例子来进行贝叶斯网络的构造。具体有向图和概率表如下图所示:

考试难度、个人聪明与否都会影响到个人成绩,另外个人聪明与否也会影响到SAT分数,而个人成绩好坏会直接影响到推荐信的质量。

学生例子中包含5个随机变量, 如下所示:

变量 含义 取值
Difficulty 课程本身难度 0=easy, 1=difficult
Intelligence 学生聪明程度 0=stupid, 1=smart
Grade 学生课程成绩 1=A, 2=B, 3=C
SAT 学生高考成绩 0=low, 1=high
Letter 可否获得推荐信 0=未获得, 1=获得

下面我们直接来用pgmpy实现上述贝叶斯网络。

导入相关模块:

# 导入pgmpy相关模块
from pgmpy.factors.discrete import TabularCPD
from pgmpy.models import BayesianModel
letter_model = BayesianModel([('D', 'G'),
                               ('I', 'G'),
                               ('G', 'L'),
                               ('I', 'S')])

构建模型框架,指定各变量之间的依赖关系:

letter_model = BayesianModel([('D', 'G'),
                               ('I', 'G'),
                               ('G', 'L'),
                               ('I', 'S')])

构建各个节点和传入概率表并指定相关参数:

# 学生成绩的条件概率分布
grade_cpd = TabularCPD(
    variable='G', # 节点名称
    variable_card=3, # 节点取值个数
    values=[[0.3, 0.05, 0.9, 0.5], # 该节点的概率表
    [0.4, 0.25, 0.08, 0.3],
    [0.3, 0.7, 0.02, 0.2]],
    evidence=['I', 'D'], # 该节点的依赖节点
    evidence_card=[2, 2] # 依赖节点的取值个数
)
# 考试难度的条件概率分布
difficulty_cpd = TabularCPD(
            variable='D',
            variable_card=2,
            values=[[0.6], [0.4]]
)
# 个人天赋的条件概率分布
intel_cpd = TabularCPD(
            variable='I',
            variable_card=2,
            values=[[0.7], [0.3]]
)
# 推荐信质量的条件概率分布
letter_cpd = TabularCPD(
            variable='L',
            variable_card=2,
            values=[[0.1, 0.4, 0.99],
            [0.9, 0.6, 0.01]],
            evidence=['G'],
            evidence_card=[3]
)
# SAT考试分数的条件概率分布
sat_cpd = TabularCPD(
            variable='S',
            variable_card=2,
            values=[[0.95, 0.2],
            [0.05, 0.8]],
            evidence=['I'],
            evidence_card=[2]
)

将包含概率表的各节点添加到模型中:

# 将各节点添加到模型中,构建贝叶斯网络
letter_model.add_cpds(
    grade_cpd, 
    difficulty_cpd,
    intel_cpd,
    letter_cpd,
    sat_cpd
)

获取模型的条件概率分布:

letter_model.get_cpds()

[<TabularCPD representing P(G:3 | I:2, D:2) at 0x7fba52206700>,
<TabularCPD representing P(D:2) at 0x7fba522066a0>,
<TabularCPD representing P(I:2) at 0x7fba52206760>,
<TabularCPD representing P(L:2 | G:3) at 0x7fba522066d0>,
<TabularCPD representing P(S:2 | I:2) at 0x7fba52206790>]

获取模型各节点之间的依赖关系:

# 获取模型各节点之间的依赖关系
letter_model.get_independencies()

(G ⟂ S | I)
(G ⟂ S | D, I)
(G ⟂ S | I, L)
(G ⟂ S | D, I, L)
(D ⟂ S, I)
(D ⟂ L | G)
(D ⟂ I | S)
(D ⟂ S | I)
(D ⟂ L | G, S)
(D ⟂ S, L | G, I)
(D ⟂ S | I, L)
(D ⟂ L | G, S, I)
(D ⟂ S | G, I, L)
(S ⟂ D)
(S ⟂ L | G)
(S ⟂ G, D, L | I)
(S ⟂ L | G, D)
(S ⟂ D, L | G, I)
(S ⟂ G, L | D, I)
(S ⟂ G, D | I, L)
(S ⟂ L | G, D, I)
(S ⟂ D | G, I, L)
(S ⟂ G | D, I, L)
(I ⟂ D)
(I ⟂ L | G)
(I ⟂ D | S)
(I ⟂ L | G, D)
(I ⟂ L | G, S)
(I ⟂ L | G, D, S)
(L ⟂ D, S, I | G)
(L ⟂ S | I)
(L ⟂ S, I | G, D)
(L ⟂ D, I | G, S)
(L ⟂ D, S | G, I)
(L ⟂ S | D, I)
(L ⟂ I | G, D, S)
(L ⟂ S | G, D, I)
(L ⟂ D | G, S, I)

进行贝叶斯推断:

# 导入pgmpy贝叶斯推断模块
from pgmpy.inference import VariableElimination
# 贝叶斯网络推断
letter_infer = VariableElimination(letter_model)
# 天赋较好且考试不难的情况下推断该学生获得推荐信质量的好坏
prob_G = letter_infer.query(
            variables=['G'],
            evidence={'I': 1, 'D': 0})
print(prob_G)

Finding Elimination Order: :

0/0 [05:27<?, ?it/s]

0/0 [00:00<?, ?it/s]

+------+----------+
| G    |   phi(G) |
+======+==========+
| G(0) |   0.9000 |
+------+----------+
| G(1) |   0.0800 |
+------+----------+
| G(2) |   0.0200 |
+------+----------+

可见当聪明的学生碰上较简单的考试时,获得第一等成绩的概率高达0.9。

标签:概率,网络,贝叶斯,test,x2,x1,节点,朴素
来源: https://www.cnblogs.com/wkfvawl/p/16252279.html