开发也能看懂的大模型:概率图模型

概率图模型(Probabilistic Graphical Model, PGM)是将概率论与图论结合的一种工具,用于表示和处理复杂的随机变量之间的关系。它用图形结构直观地表达变量之间的依赖关系,同时利用概率计算进行推理和学习。


1. 概率图模型的核心概念

1.1 基本组成

  • 节点:代表随机变量,可以是离散变量(如天气=晴/雨)或连续变量(如温度=20℃)。

  • :表示随机变量之间的依赖关系。

    • 有向边:因果关系,表示一个变量直接影响另一个变量。
    • 无向边:表示变量之间的相互关联,没有特定方向。
  • 概率分布:描述每个变量的可能取值及其概率,并结合条件概率描述依赖关系。

1.2 两种主要类型

  1. 贝叶斯网络(Bayesian Network)

    • 有向无环图(Directed Acyclic Graph, DAG)。

    • 节点表示随机变量,边表示条件依赖关系。

    • 例如:

      • 节点:天气(晴、雨)、草坪湿润(是、否)。
      • 边:天气 → 草坪湿润(天气影响草坪湿润)。
    • 优点:能表达因果关系,适用于动态系统建模。

  2. 马尔科夫随机场(Markov Random Field, MRF)

    • 无向图

    • 节点表示随机变量,边表示相邻变量的关联性。

    • 例如:

      • 在图像分割中,相邻像素通常有相似的颜色。
    • 优点:适用于不需要方向性假设的模型,如图像处理和空间关系建模。


2. 概率图模型的主要功能

2.1 表达变量的依赖关系

  • PGM通过图结构直观地展示变量之间的条件独立性。
  • 例如,在贝叶斯网络中,如果 A→B→C,则 C 和 A 是条件独立的(给定 B)。

2.2 推理

  • 根据观测数据对未知变量进行推断。

  • 例如:

    • 已知天气是雨天,推断草坪湿润的概率。
    • 在医疗诊断中,已知某些症状,推断疾病的可能性。

2.3 学习

  • 从数据中学习模型的结构和参数。
  • 例如,从大量图像数据中学习像素之间的概率关系。

3. 概率图模型的优势

  1. 直观性:通过图结构表达变量之间的复杂依赖关系,比单纯用数学公式描述更易理解。
  2. 可扩展性:适合处理大规模多变量系统。
  3. 通用性:适用于从时间序列(动态贝叶斯网络)到空间关系(马尔科夫随机场)等多种场景。

4. 应用场景

  1. 自然语言处理(NLP)

    • 语法分析:词之间的依赖关系建模(如隐马尔可夫模型,HMM)。
    • 主题建模:文档中主题的概率分布建模(如LDA)。
  2. 计算机视觉

    • 图像分割:通过马尔科夫随机场建模像素之间的依赖关系。
    • 目标识别:通过条件随机场(CRF)建模物体之间的关系。
  3. 医疗诊断

    • 基于症状预测疾病(如贝叶斯网络表示疾病和症状的因果关系)。
    • 基于患者历史数据建模病情发展。
  4. 推荐系统

    • 利用用户行为和物品特征建模(如用户对电影评分的概率分布)。
  5. 机器人学

    • 路径规划和状态估计(如动态贝叶斯网络建模传感器数据)。

案例:基于贝叶斯网络的医疗诊断

1. 背景

医疗诊断中,医生经常需要根据症状(咳嗽、发烧)推断可能的疾病(如流感、肺炎)。这是一个典型的不确定性推理问题,非常适合用贝叶斯网络来建模。


2. 数据集:开源的"疾病与症状关系"数据

数据集Symptom Disease Data(公开健康数据集,例如 [Kaggle 的疾病与症状数据])。

包含以下信息:

  • 随机变量:疾病(Disease),症状(Symptoms)。

  • 示例数据:疾病 D 与症状 S1​,S2​,S3​ 的条件概率,如:

    • P(咳嗽∣流感)=0.8 (咳嗽患流感的概率0.8)
    • P(咳嗽∣肺炎)=0.7

3. 问题建模

随机变量:

  1. 疾病变量

    • D:可能的疾病(如流感、肺炎、普通感冒)。
  2. 症状变量

    • S1:是否有咳嗽
    • S2:是否有发烧
    • S3:是否感到乏力

网络结构:

贝叶斯网络用有向无环图(DAG)表示疾病和症状的因果关系:

markdown 复制代码
    疾病(D)
     ↘  ↙  ↘
    咳嗽   发烧   乏力

条件概率表(CPT)示例:

  1. 疾病的先验概率

    • P(流感)=0.3,P(肺炎)=0.2,P(普通感冒)=0.5
  2. 症状的条件概率(示例数据):

    • P(咳嗽∣流感)=0.8,P(咳嗽∣肺炎)=0.7,P(咳嗽∣普通感冒)=0.6
    • 类似地定义发烧、乏力的条件概率。

4. 任务

  • 目标 1:已知某人有咳嗽和发烧,计算他患流感的概率 P(流感∣咳嗽,发烧)
  • 目标 2:更新贝叶斯网络模型,基于更多症状推断概率。

5. 实现步骤

5.1 导入必要工具

我们使用 Python 和 pgmpy 库,专门用于概率图模型的构建和推断。

python 复制代码
import numpy as np
import pandas as pd
from pgmpy.models import BayesianNetwork
from pgmpy.inference import VariableElimination

5.2 构建贝叶斯网络

定义疾病和症状之间的关系及条件概率表(CPT)。

python 复制代码
# 定义贝叶斯网络结构
model = BayesianNetwork([('Disease', 'Cough'), 
                         ('Disease', 'Fever'), 
                         ('Disease', 'Fatigue')])

# 定义先验概率(疾病)
cpd_disease = pd.DataFrame({
    'Disease': ['Flu', 'Pneumonia', 'Cold'],
    'Probability': [0.3, 0.2, 0.5] # [流感, 肺炎, 普通感冒]
})

# 定义咳嗽症状的条件概率表
cpd_cough = pd.DataFrame({
    'Disease': ['Flu', 'Pneumonia', 'Cold'],
    'Cough_Yes': [0.8, 0.7, 0.6],
    'Cough_No': [0.2, 0.3, 0.4]
})
# 定义发烧症状的条件概率表
cpd_fever = pd.DataFrame({
    'Disease': ['Flu', 'Pneumonia', 'Cold'],
    'Fever_Yes': [0.9, 0.8, 0.3],
    'Fever_No': [0.1, 0.2, 0.7]
})

cpd_fatigue = pd.DataFrame({
    'Disease': ['Flu', 'Pneumonia', 'Cold'],
    'Fatigue_Yes': [0.7, 0.6, 0.4],
    'Fatigue_No': [0.3, 0.4, 0.6]
})
  • 如果患者患有流感(Flu):咳嗽的概率为 P=0.8,不咳嗽的概率为 P=0.2。
  • 如果患者患有肺炎(Pneumonia):咳嗽的概率为 P=0.7,不咳嗽的概率为 P=0.3。
  • 如果患者患有流感(Flu):发烧的概率为 P=0.9,不发烧的概率为 P=0.1。

5.3 推理(Inference)

pgmpy 的推理工具进行推断。

python 复制代码
# 加载条件概率到网络
from pgmpy.factors.discrete import TabularCPD

model.add_cpds(
    TabularCPD(variable='Disease', variable_card=3, 
               values=[[0.3], [0.2], [0.5]]),
    TabularCPD(variable='Cough', variable_card=2, 
               values=[[0.8, 0.7, 0.6], [0.2, 0.3, 0.4]], 
               evidence=['Disease'], evidence_card=[3]),
    TabularCPD(variable='Fever', variable_card=2, 
               values=[[0.9, 0.8, 0.3], [0.1, 0.2, 0.7]], 
               evidence=['Disease'], evidence_card=[3]),
    TabularCPD(variable='Fatigue', variable_card=2, 
               values=[[0.7, 0.6, 0.4], [0.3, 0.4, 0.6]], 
               evidence=['Disease'], evidence_card=[3])
)

# 验证模型
assert model.check_model()

# 推理工具
inference = VariableElimination(model)

# 计算:已知咳嗽和发烧,患流感的概率
result = inference.query(variables=['Disease'], evidence={'Cough': 1, 'Fever': 1})
print(result)

TabularCPD(variable='Fever', variable_card=2, values=[[0.9, 0.8, 0.3], [0.1, 0.2, 0.7]]解释:

字段解析

  1. variable='Fever'

    • 定义条件概率分布的目标变量是 Fever

    • Fever 是一个二值变量,即它可以取两个状态:

      • Fever=Yes(表示发烧)
      • Fever=No(表示不发烧)
  2. variable_card=2

    • 定义 Fever 变量的基数 (cardinality),即 Fever 只有两个可能的状态:YesNo
  3. values=[[0.9, 0.8, 0.3], [0.1, 0.2, 0.7]]

    • 定义 Fever 的条件概率表(CPT),每一列表示在不同疾病条件下 Fever=YesFever=No 的概率。

    • 具体含义如下:

      Disease Fever=Yes (P) Fever=No (P)
      Disease[0] (流感) 0.9 0.1
      Disease[1] (肺炎) 0.8 0.2
      Disease[2] (感冒) 0.3 0.7
      • 在流感的情况下(Disease[0]):

        • 发烧的概率P=0.9
        • 不发烧的概率 P=0.1
      • 在肺炎的情况下(Disease[1]):

        • 发烧的概率 P=0.8
        • 不发烧的概率 P=0.2
      • 在普通感冒的情况下(Disease[2]):

        • 发烧的概率 P=0.3
        • 不发烧的概率 P=0.7
  4. evidence=['Disease']

    • Fever 的概率是条件概率,依赖于随机变量 Disease 的取值。
    • 即,Fever 的状态由 Disease 的状态决定。
  5. evidence_card=[3]

    • 定义条件变量 Disease 的基数为 3(因为 Disease 有三种可能的状态:流感、肺炎、普通感冒)。

逻辑意义

该 CPD 表明:

  • 不同疾病对发烧的影响不同。

  • 比如:

    • 流感(Disease[0])的患者有很高的概率(0.9)发烧。
    • 肺炎(Disease[1])的患者也有较高的概率(0.8)发烧。
    • 而普通感冒(Disease[2])的患者发烧概率较低(0.3)。

通过这种条件概率表,可以用贝叶斯网络对症状(如发烧)和疾病之间的因果关系进行建模。


6. 结果分析

其中:

  • Disease(0)Disease(1)Disease(2) 分别代表三种疾病("流感"、"肺炎"和"普通感冒")。
  • phi(Disease) 表示每种疾病的后验概率,即在给定证据(咳嗽和发烧)下,各疾病的发生概率。

具体分析

  1. Disease(2) 的概率为 0.8861(88.61%):

    • 这是后验概率中最高的值,表明在观测到咳嗽和发烧的情况下,Disease(2) (普通感冒)最有可能是患者的疾病。
    • 高概率的原因可能是普通感冒的症状(咳嗽和发烧)条件概率较高,或该疾病的先验概率较大(如 50%)

完整代码

python 复制代码
import numpy as np
from pgmpy.models import BayesianNetwork
from pgmpy.factors.discrete import TabularCPD
from pgmpy.inference import VariableElimination

# 1. 定义贝叶斯网络结构
model = BayesianNetwork([('Disease', 'Cough'), 
                         ('Disease', 'Fever'), 
                         ('Disease', 'Fatigue')])

# 2. 定义条件概率表(CPT)
# 疾病的先验概率
cpd_disease = TabularCPD(
    variable='Disease', variable_card=3, 
    values=[[0.3], [0.2], [0.5]]  # [流感, 肺炎, 普通感冒]
)

# 咳嗽的条件概率
cpd_cough = TabularCPD(
    variable='Cough', variable_card=2,
    values=[[0.8, 0.7, 0.6],  # P(Cough=Yes | Disease)
            [0.2, 0.3, 0.4]], # P(Cough=No | Disease)
    evidence=['Disease'], evidence_card=[3]
)

# 发烧的条件概率
cpd_fever = TabularCPD(
    variable='Fever', variable_card=2,
    values=[[0.9, 0.8, 0.3],  # P(Fever=Yes | Disease)
            [0.1, 0.2, 0.7]], # P(Fever=No | Disease)
    evidence=['Disease'], evidence_card=[3]
)

# 乏力的条件概率
cpd_fatigue = TabularCPD(
    variable='Fatigue', variable_card=2,
    values=[[0.7, 0.6, 0.4],  # P(Fatigue=Yes | Disease)
            [0.3, 0.4, 0.6]], # P(Fatigue=No | Disease)
    evidence=['Disease'], evidence_card=[3]
)

# 3. 将CPT添加到模型中
model.add_cpds(cpd_disease, cpd_cough, cpd_fever, cpd_fatigue)

# 验证模型是否正确
assert model.check_model()

# 4. 创建推理工具
inference = VariableElimination(model)

# 5. 推理:已知咳嗽和发烧,计算疾病概率分布
result = inference.query(variables=['Disease'], evidence={'Cough': 1, 'Fever': 1})

# 输出结果
print(result)
相关推荐
加瓦点灯2 分钟前
深挖 JVM 关闭钩子与 Signal 机制:优雅停机背后的秘密
后端
Yrrr13 分钟前
Redis 持久化机制详解:RDB、AOF 原理与面试最佳实践(AOF篇)
数据库·redis·面试·职场和发展
程序小武16 分钟前
Python面向对象编程-类方法与静态方法
后端
加瓦点灯42 分钟前
通过 Netty 的 Pipeline 学习责任链设计模式
后端
加密社44 分钟前
Solana 开发实战:Rust 客户端调用链上程序全流程
开发语言·后端·rust
一入JAVA毁终身1 小时前
面试第三期
面试·职场和发展
YGGP1 小时前
吃透 Golang 基础:Goroutine
后端·golang
晴殇i1 小时前
3 分钟掌握图片懒加载核心技术:面试攻略
前端·面试·trae
天天摸鱼的java工程师2 小时前
如何实现一个红包系统,支持并发抢红包?
后端