bayesian lab finished

This commit is contained in:
2026-01-01 17:27:18 +08:00
parent c8ea743250
commit 9efc325c87
9 changed files with 11850 additions and 4916 deletions

View File

@ -0,0 +1,132 @@
import random
# CPTs
# P(C)
P_C = {True: 0.5, False: 0.5}
# P(S | C)
P_S_given_C = {
True: {True: 0.10, False: 0.90}, # C=T
False: {True: 0.50, False: 0.50} # C=F
}
# P(R | C)
P_R_given_C = {
True: {True: 0.80, False: 0.20}, # C=T
False: {True: 0.20, False: 0.80} # C=F
}
# P(W | S, R)
P_W_given_SR = {
(True, True): {True: 0.99, False: 0.01},
(True, False): {True: 0.90, False: 0.10},
(False, True): {True: 0.90, False: 0.10},
(False, False): {True: 0.00, False: 1.00}
}
def sample_variable(prob_true):
"""Returns True with probability prob_true, else False"""
return random.random() < prob_true
def get_prior_sample():
"""Generates a sample from the joint distribution P(C, S, R, W)"""
c = sample_variable(P_C[True])
s = sample_variable(P_S_given_C[c][True])
r = sample_variable(P_R_given_C[c][True])
w = sample_variable(P_W_given_SR[(s, r)][True])
return {'C': c, 'S': s, 'R': r, 'W': w}
def rejection_sampling(query_var, query_val, evidence, num_samples):
"""
Estimates P(query_var = query_val | evidence) using Rejection Sampling.
evidence is a dict, e.g., {'S': True, 'W': True}
"""
consistent_count = 0
query_match_count = 0
for _ in range(num_samples):
sample = get_prior_sample()
# Check if sample is consistent with evidence
is_consistent = True
for var, val in evidence.items():
if sample[var] != val:
is_consistent = False
break
if is_consistent:
consistent_count += 1
if sample[query_var] == query_val:
query_match_count += 1
if consistent_count == 0:
return 0.0 # Avoid division by zero
return query_match_count / consistent_count
def likelihood_weighting(query_var, query_val, evidence, num_samples):
"""
Estimates P(query_var = query_val | evidence) using Likelihood Weighting.
evidence is a dict, e.g., {'S': True, 'W': True}
"""
weighted_counts = {True: 0.0, False: 0.0}
for _ in range(num_samples):
weight = 1.0
sample = {}
# C
if 'C' in evidence:
sample['C'] = evidence['C']
weight *= P_C[sample['C']]
else:
sample['C'] = sample_variable(P_C[True])
# S
if 'S' in evidence:
sample['S'] = evidence['S']
weight *= P_S_given_C[sample['C']][sample['S']]
else:
sample['S'] = sample_variable(P_S_given_C[sample['C']][True])
# R
if 'R' in evidence:
sample['R'] = evidence['R']
weight *= P_R_given_C[sample['C']][sample['R']]
else:
sample['R'] = sample_variable(P_R_given_C[sample['C']][True])
# W
if 'W' in evidence:
sample['W'] = evidence['W']
weight *= P_W_given_SR[(sample['S'], sample['R'])][sample['W']]
else:
sample['W'] = sample_variable(P_W_given_SR[(sample['S'], sample['R'])][True])
# Accumulate weight for the value of the query variable in this sample
weighted_counts[sample[query_var]] += weight
total_weight = sum(weighted_counts.values())
if total_weight == 0:
return 0.0
return weighted_counts[query_val] / total_weight
if __name__ == "__main__":
evidence = {'S': True, 'W': True}
query_var = 'R'
query_val = True
# Exact Calculation (calculated manually in thought process)
# Numerator: 0.0891
# Denominator: 0.2781
exact_prob = 0.0891 / 0.2781
print(f"Exact Probability P(R=T | S=T, W=T): {exact_prob:.6f}")
print("-" * 60)
print(f"{'Samples':<10} | {'Rejection Sampling':<20} | {'Likelihood Weighting':<20}")
print("-" * 60)
for N in [100, 1000, 10000, 100000, 1000000]:
rs_result = rejection_sampling(query_var, query_val, evidence, N)
lw_result = likelihood_weighting(query_var, query_val, evidence, N)
print(f"{N:<10} | {rs_result:<20.6f} | {lw_result:<20.6f}")

57
bayesian/generate_data.py Normal file
View File

@ -0,0 +1,57 @@
import pandas as pd
import numpy as np
# 定义真实的条件概率表 (Ground Truth CPTs)
# 学生需要从生成的数据中“反向学习”出这些概率
PROBS = {
'IsSmoker': 0.2,
'VisitAsia': 0.05,
'HasLungCancer': { # Given IsSmoker
(1,): 0.1,
(0,): 0.01
},
'HasTuberculosis': { # Given VisitAsia
(1,): 0.08,
(0,): 0.001
},
'XRayPositive': { # Given HasLungCancer, HasTuberculosis
(1, 1): 0.98,
(1, 0): 0.95,
(0, 1): 0.90,
(0, 0): 0.05
},
'HasDyspnea': { # Given HasLungCancer
(1,): 0.7,
(0,): 0.2
}
}
def generate_data(num_samples=1000):
data = []
for _ in range(num_samples):
# Sample from parent nodes
is_smoker = np.random.binomial(1, PROBS['IsSmoker'])
visit_asia = np.random.binomial(1, PROBS['VisitAsia'])
# Sample from children nodes based on parents
p_lc = PROBS['HasLungCancer'][(is_smoker,)]
has_lc = np.random.binomial(1, p_lc)
p_tb = PROBS['HasTuberculosis'][(visit_asia,)]
has_tb = np.random.binomial(1, p_tb)
p_xray = PROBS['XRayPositive'][(has_lc, has_tb)]
xray_pos = np.random.binomial(1, p_xray)
p_dys = PROBS['HasDyspnea'][(has_lc,)]
has_dys = np.random.binomial(1, p_dys)
data.append([is_smoker, visit_asia, has_lc, has_tb, xray_pos, has_dys])
df = pd.DataFrame(data, columns=['IsSmoker', 'VisitAsia', 'HasLungCancer',
'HasTuberculosis', 'XRayPositive', 'HasDyspnea'])
df.to_csv('data.csv', index=False)
print(f"Generated data.csv with {num_samples} samples.")
if __name__ == '__main__':
generate_data(num_samples=2000)

6702
bayesian/homework.pdf Normal file

File diff suppressed because one or more lines are too long

289
bayesian/homework.typ Normal file
View File

@ -0,0 +1,289 @@
#import "@preview/cetz:0.3.3"
#set text(font: ("Noto Sans CJK SC", "Noto Serif CJK SC"), lang: "zh")
#set page(paper: "a4", margin: (x: 2cm, y: 2cm))
#set heading(numbering: "1.")
#let answer(body) = block(
fill: luma(240),
stroke: (left: 2pt + blue),
inset: 10pt,
radius: 2pt,
width: 100%,
body
)
#align(center)[
#text(size: 18pt, weight: "bold")[第13-14章 概率与贝叶斯网络 习题解答]
#v(1em)
// *生成时间:* #datetime.today().display()
]
= 题目 1
*题意:* 已知 $P(a) = 0.3$, $P(b | a) = 0.2$, $P(c | a) = 0.5$。比较 $P(a and b)$ $P(a and c)$
#answer[
根据乘法公式 $P(x and y) = P(x)P(y|x)$
$ P(a and b) &= P(a) dot P(b | a) = 0.3 times 0.2 = 0.06 \
P(a and c) &= P(a) dot P(c | a) = 0.3 times 0.5 = 0.15 $
因为 $0.06 < 0.15$,所以 *$P(a and b) < P(a and c)$*
*答案B*
]
= 题目 2
*题意:* $P(a or b)=0.7$, $P(a)=0.4$, $P(b)=0.5$,求 $P(a and b)$
#answer[
根据概率加法公式(容斥原理):
$ P(a or b) = P(a) + P(b) - P(a and b) $
代入已知数值:
$ 0.7 = 0.4 + 0.5 - P(a and b) \
P(a and b) = 0.9 - 0.7 = 0.2 $
*答案0.2*
]
= 题目 3
*数据:* 全联合概率分布表如下Cavity, Toothache, Catch
#table(
columns: (auto, auto, auto, auto, auto),
inset: 8pt,
align: center,
[], [T, Catch], [T, $not$ Catch], [$not$ T, Catch], [$not$ T, $not$ Catch],
[Cavity], [0.108], [0.012], [0.072], [0.008],
[$not$ Cavity], [0.016], [0.064], [0.144], [0.576]
)
#answer[
*1. 计算 $P("Toothache" or not "Cavity")$*
利用补集思想:$P(A) = 1 - P(not A)$
事件的补集是 $not "Toothache" and "Cavity"$
对应表格中的项为:(Cavity, $not$ T, Catch) (Cavity, $not$ T, $not$ Catch)。
$ P(not T and "Cav") = 0.072 + 0.008 = 0.080 $
$ P(T or not "Cav") = 1 - 0.080 = 0.92 $
*2. 计算 $P(not "toothache" or "catch")$*
补集是 $"toothache" and not "catch"$
对应表格列为 (T, $not$ Catch),即第 2 列。
$ P(T and not "Catch") = 0.012 ("Cav") + 0.064 (not "Cav") = 0.076 $
$ P(not T or "Catch") = 1 - 0.076 = 0.924 $
*3. 计算 $P("Toothache" or not "Cavity" | not "catch")$ 和 $P(not "catch" | "Toothache" or not "Cavity")$*
$A = "Toothache" or not "Cavity"$, $B = not "catch"$
- *计算 $P(B)$*: Sum of all $not$ Catch columns (Col 2, Col 4).
$P(B) = (0.012 + 0.064) + (0.008 + 0.576) = 0.076 + 0.584 = 0.66$
- *计算 $P(A and B)$*: $not$ Catch 列中满足 $T or not "Cav"$ 的项。
- (Cav, T, $not$ C): 0.012 (满足 T)
- ($not$ Cav, T, $not$ C): 0.064 (满足 T)
- ($not$ Cav, $not$ T, $not$ C): 0.576 (满足 $not$ Cav)
- (Cav, $not$ T, $not$ C): 0.008 (不满足既无T也无$not$Cav)
Sum $= 0.012 + 0.064 + 0.576 = 0.652$
结果 1: $P(A | B) = 0.652 / 0.66 approx 0.9879$
结果 2: $P(B | A) = P(A and B) / P(A) = 0.652 / 0.92 approx 0.7087$ (其中 P(A) 来自第1小问)
*4. 判断 Cavity 与 Toothache 是否独立*
$ P("Cav") &= 0.108+0.012+0.072+0.008 = 0.2 \
P("Toothache") &= 0.108+0.012+0.016+0.064 = 0.2 \
P("Cav" and "T") &= 0.108 + 0.012 = 0.12 $
检验:$P("Cav") times P("T") = 0.2 times 0.2 = 0.04$
因为 $0.12 != 0.04$,所以两者 *不独立*
]
= 题目 4
*题意:* $X, Y$ 条件独立于 $Z$(即 $X perp Y | Z$$Y, W$ 条件独立于 $Z$(即 $Y perp W | Z$)。问 $X, W$ 是否条件独立于 $Z$
#answer[
*结论:不能。* 条件独立性不具备传递性。
*反例证明:*
假设 $Z$ 是一个公平的硬币投掷0 1
$X = Z$$X$ 完全依赖于 $Z$)。
$W = Z$$W$ 完全依赖于 $Z$)。
$Y$ 是一个与 $X, W, Z$ 都完全独立的随机变量(例如掷骰子)。
1. *检查 $X, Y$ 关于 $Z$ 的独立性*:给定 $Z$ $X$ 变为常数。常数与任何变量独立,故成立。
2. *检查 $Y, W$ 关于 $Z$ 的独立性*:同理,给定 $Z$$W$ 变为常数,故成立。
3. *检查 $X, W$ 关于 $Z$ 的独立性*
给定 $Z$$X$ $W$ 的值完全确定且相同(例如若 $Z=1$,则 $X=1, W=1$)。虽然在 $Z$ 固定的情况下它们的方差为0技术上可视作独立但如果我们考虑一种因果结构
$X$ $W$ 为同一变量的两个副本。显然它们是强相关的。
更直观的例子:$X$ $W$ 互为因果或由共同隐变量控制,而它们都与 $Y$ 独立。仅仅知道它们分别与 $Y$ 独立,无法切断 $X$ $W$ 之间的联系。
]
= 题目 5
*题意:* 罕见病检测。$P(D)=0.001$
检测A$P(+|D)=0.95, P(+|not D)=0.05$
检测B$P(+|D)=0.90, P(+|not D)=0.10$
#answer[
*a. 单次检测 A 为阳性,求 $P(D|A+)$*
使用贝叶斯公式:
$ P(D|A+) = (P(A+|D)P(D)) / P(A+) $
$ P(A+) &= P(A+|D)P(D) + P(A+|not D)P(not D) \
&= 0.95 times 0.001 + 0.05 times 0.999 \
&= 0.00095 + 0.04995 = 0.0509 $
$ P(D|A+) &= 0.00095 / 0.0509 approx 0.0187 (1.87%) $
*b. 两次检测 A 和 B 均为阳性,求 $P(D|A+, B+)$*
由于检测独立Naive Bayes 假设):
$ P(A+, B+ | D) = 0.95 times 0.90 = 0.855 $
$ P(A+, B+ | not D) = 0.05 times 0.10 = 0.005 $
$ P(D | A+, B+) &= (P(A+, B+ | D)P(D)) / (P(A+, B+ | D)P(D) + P(A+, B+ | not D)P(not D)) \
&= (0.855 times 0.001) / (0.855 times 0.001 + 0.005 times 0.999) \
&= 0.000855 / (0.000855 + 0.004995) \
&= 0.000855 / 0.00585 approx 0.1462 (14.62%) $
*c. 解释*
联合检测通过引入第二次独立测试,极大地降低了*假阳性率*(从 0.05 降至 $0.05 times 0.10 = 0.005$)。虽然真阳性率也略有下降,但分母中占主导地位的假阳性项(由 $P(not D)$ 权重放大)被大幅削减,从而显著提升了后验概率。
]
= 题目 6
*场景:* 骑车(B) 取决于 天气(W) 熬夜(S)。
$P(W="Sun")=0.7, P(S="Yes")=0.4$
CPT 已知。
#answer[
*a. 贝叶斯网络与 CPT*
结构:$W -> B <- S$ (V-structure)
#cetz.canvas({
import cetz.draw: *
let r = 0.8
// Nodes
circle((0, 0), radius: r, name: "B")
content("B", "B (骑车)")
circle((-2, 3), radius: r, name: "W")
content("W", "W (天气)")
circle((2, 3), radius: r, name: "S")
content("S", "S (熬夜)")
// Edges
line("W", "B", mark: (end: ">"))
line("S", "B", mark: (end: ">"))
})
*条件概率表 (CPT) for B:*
#table(
columns: 3,
align: center,
[W (天气)], [S (熬夜)], [P(B=是 | W, S)],
[晴 (Sun)], [否 (No)], [0.9],
[晴 (Sun)], [是 (Yes)], [0.6],
[雨 (Rain)], [否 (No)], [0.2],
[雨 (Rain)], [是 (Yes)], [0.1]
)
*b. 推理:已知骑车(B=Yes),求天气概率*
我们需要计算 $P(W | B="Yes")$。根据贝叶斯法则:$P(W|B) = P(B|W)P(W) / P(B)$。
首先计算边缘概率 $P(B="Yes")$。
$ P(B=y) = sum_(w, s) P(B=y|w,s)P(w)P(s) $
因 W 和 S 独立,联合概率直接相乘。
1. $W="Sun", S="No"$: $0.9 times 0.7 times 0.6 = 0.378$
2. $W="Sun", S="Yes"$: $0.6 times 0.7 times 0.4 = 0.168$
3. $W="Rain", S="No"$: $0.2 times 0.3 times 0.6 = 0.036$
4. $W="Rain", S="Yes"$: $0.1 times 0.3 times 0.4 = 0.012$
$ P(B="Yes") = 0.378 + 0.168 + 0.036 + 0.012 = 0.594 $
计算 $P(W="Sun" | B="Yes")$:
分子为 W=Sun 的所有情况之和项1 + 项2
$ P(B=y, W="Sun") = 0.378 + 0.168 = 0.546 $
$ P(W="Sun" | B="Yes") = 0.546 / 0.594 approx 0.919 $
同理,$P(W="Rain" | B="Yes") = (0.036 + 0.012) / 0.594 approx 0.081$。
*结论:这天最可能是晴天。*
]
= 题目 7
*智能健康助手:* 变量 S(吸烟), G(基因), L(肺癌), C(咳嗽), X(胸片)。
关系:$S->L, G->L, S->C, L->C, L->X$。
#answer[
*问题 1贝叶斯网络图*
#align(center)[
#cetz.canvas({
import cetz.draw: *
// Manually positioning nodes for clarity
let r = 0.5
circle((0, 0), radius: r, name: "L")
content("L", "L")
circle((-2, 2), radius: r, name: "S")
content("S", "S")
circle((2, 2), radius: r, name: "G")
content("G", "G")
circle((-1, -2), radius: r, name: "C")
content("C", "C")
circle((1, -2), radius: r, name: "X")
content("X", "X")
line("S", "L", mark: (end: ">"))
line("G", "L", mark: (end: ">"))
line("L", "X", mark: (end: ">"))
line("L", "C", mark: (end: ">"))
// S -> C 直接边
line("S", "C", mark: (end: ">"))
})
]
*问题 2概率推理 $P(L="Yes" | C="No", X="Yes")$*
$alpha$ 为归一化常数。我们需要计算 $P(L=y, C=n, X=y)$ $P(L=n, C=n, X=y)$
公式分解:$P(S,G,L,C,X) = P(S)P(G)P(L|S,G)P(C|L,S)P(X|L)$
求和消除 S, G
$ P(L, C, X) = P(X|L) sum_S sum_G P(C|L,S) P(L|S,G) P(S) P(G) $
*Case 1: L = Yes* (且 $C=n, X=y$)
因子 $P(X=y|L=y) = 0.9$
内部求和 $Sigma_(L=y)$:
- $S=y, G=h$: $P(C=n|L=y,S=y)P(L=y|S=y,G=h)P(S=y)P(G=h) = 0.2 times 0.6 times 0.3 times 0.2 = 0.0072$
- $S=y, G=l$: $0.2 times 0.3 times 0.3 times 0.8 = 0.0144$
- $S=n, G=h$: $P(C=n|L=y,S=n)P(L=y|S=n,G=h)P(S=n)P(G=h) = 0.4 times 0.4 times 0.7 times 0.2 = 0.0224$
- $S=n, G=l$: $0.4 times 0.1 times 0.7 times 0.8 = 0.0224$
$Sigma_(L=y) = 0.0072 + 0.0144 + 0.0224 + 0.0224 = 0.0664$
$P(L=y, C=n, X=y) = 0.9 times 0.0664 = 0.05976$
*Case 2: L = No* (且 $C=n, X=y$)
因子 $P(X=y|L=n) = 0.1$
内部求和 $Sigma_(L=n)$:
- $S=y, G=h$: $P(C=n|L=n,S=y)P(L=n|S=y,G=h)P(S=y)P(G=h) = 0.7 times 0.4 times 0.3 times 0.2 = 0.0168$
- $S=y, G=l$: $0.7 times 0.7 times 0.3 times 0.8 = 0.1176$
- $S=n, G=h$: $P(C=n|L=n,S=n)P(L=n|S=n,G=h)P(S=n)P(G=h) = 0.9 times 0.6 times 0.7 times 0.2 = 0.0756$
- $S=n, G=l$: $0.9 times 0.9 times 0.7 times 0.8 = 0.4536$
$Sigma_(L=n) = 0.0168 + 0.1176 + 0.0756 + 0.4536 = 0.6636$
$P(L=n, C=n, X=y) = 0.1 times 0.6636 = 0.06636$
*最终归一化:*
$ P(L="Yes" | ...) &= 0.05976 / (0.05976 + 0.06636) \
&= 0.05976 / 0.12612 approx 0.4738 $
*答案47.38%*
]

177
bayesian/labtemplate.typ Executable file
View File

@ -0,0 +1,177 @@
#let times = "Times LT Pro"
#let times = "Times New Roman"
#let song = (times, "Noto Serif CJK SC")
#let hei = (times, "Noto Sans CJK SC")
#let kai = (times, "Noto Serif CJK SC")
#let xbsong = (times, "Noto Serif CJK SC")
#let fsong = (times, "Noto Serif CJK SC")
#let code = (times, "JetBrains Mono")
#let nudtlabpaper(title: "",
author: "",
id: "",
training_type:"",
grade: "",
major: "",
department: "",
advisor: "",
jobtitle: "",
lab: "",
date: "",
header_str: "",
simple_cover: "",
body) = {
// Set the document's basic properties.
set document(author: author, title: title)
set page(
margin: (left: 30mm, right: 30mm, top: 30mm, bottom: 30mm),
)
// Title row.
v(158pt)
align(center)[
#block(text(weight: 700, size: 30pt, font: hei, tracking: 15pt, "人工智能实验报告"))
]
// align(center)[
// #block(text(weight: 700, size: 30pt, font: song, tracking: 15pt, "本科实验报告"))
// ]
v(83pt)
pad(
left: 1em,
right: 1em,
grid(
columns: (80pt, 1fr),
rows: (17pt, auto),
text(weight: 700, size: 16pt, font: song, "实验名称:"),
align(center, text(weight: "regular", size: 16pt, font: song, title)),
text(""),
line(length: 100%)
)
// #block(text(weight: 700, 1.75em, title))
// underline(text(weight: 700, size: 16pt, font: song, title))
)
// Author information.
v(82.5pt)
if simple_cover {
pad(
left: 10%,
right: 10%,
grid(
columns: (100pt, 1fr),
rows: (15pt, 8pt, 15pt, 8pt, 15pt, 8pt),
text(size: 14pt, font: song, "学员姓名:"),
align(center, text(size: 14pt, font: song, author)),
text(""),
line(length: 100%),
text(size: 14pt, font: song, "学 号:"),
align(center, text(size: 14pt, font: times, id)),
text(""),
line(length: 100%),
text(size: 14pt, font: song, "实验日期:"),
align(center, text(size: 14pt, font: song, date)),
text(""),
line(length: 100%),
)
)
} else {
grid(
columns: (0.25fr, 0.25fr, 0.25fr, 0.25fr),
rows: (15pt, 8pt, 15pt, 8pt, 15pt, 8pt, 15pt, 8pt, 15pt),
text(size: 14pt, font: song, tracking: 10pt, "学员姓名"),
align(center, text(size: 14pt, font: song, author)),
text(size: 14pt, font: song, tracking: 54pt, "学号"),
align(center, text(size: 14pt, font: times, id)),
text(""),
line(length: 100%),
text(""),
line(length: 100%),
text(size: 14pt, font: song, tracking: 9pt, "培养类型"),
align(center, text(size: 14pt, font: song, training_type)),
text(size: 14pt, font: song, tracking: 54pt, "年级"),
align(center, text(size: 14pt, font: times, grade)),
text(""),
line(length: 100%),
text(""),
line(length: 100%),
text(size: 14pt, font: song, tracking: 54pt, "专业"),
align(center, text(size: 14pt, font: song, major)),
text(size: 14pt, font: song, tracking: 9pt, "所属学院"),
align(center, text(size: 14pt, font: song, department)),
text(""),
line(length: 100%),
text(""),
line(length: 100%),
text(size: 14pt, font: song, tracking: 9pt, "指导教员"),
align(center, text(size: 14pt, font: song, advisor)),
text(size: 14pt, font: song, tracking: 54pt, "职称"),
align(center, text(size: 14pt, font: song, jobtitle)),
text(""),
line(length: 100%),
text(""),
line(length: 100%),
text(size: 14pt, font: song, tracking: 20pt, "实验室"),
align(center, text(size: 14pt, font: song, lab)),
text(size: 14pt, font: song, tracking: 9pt, "实验时间"),
align(center, text(size: 14pt, font: song, date)),
text(""),
line(length: 100%),
text(""),
line(length: 100%),
)
}
v(50.5pt)
align(center, text(font: hei, size: 15pt, "国防科技大学教育训练部制"))
pagebreak()
set page(
margin: (left: 30mm, right: 30mm, top: 30mm, bottom: 30mm),
numbering: "i",
number-align: center,
)
v(14pt)
align(center)[
#block(text(font: hei, size: 14pt, "《本科实验报告》填写说明"))
]
v(14pt)
text("")
par(first-line-indent: 2em, text(font: song, size: 12pt, "实验报告内容编排应符合以下要求:"))
par(first-line-indent: 2em, text(font: fsong, size: 12pt, "1采用A421cm×29.7cm白色复印纸单面黑字。上下左右各侧的页边距均为3cm缺省文档网格字号为小4号中文为宋体英文和阿拉伯数字为Times New Roman每页30行每行36字页脚距边界为2.5cm页码置于页脚、居中采用小5号阿拉伯数字从1开始连续编排封面不编页码。"))
par(first-line-indent: 2em, text(font: fsong, size: 12pt, "2报告正文最多可设四级标题字体均为黑体第一级标题字号为4号其余各级标题为小4号标题序号第一级用“一、”、“二、”……第二级用“”、“” ……第三级用“1.”、“2.” ……第四级用“1”、“2” ……,分别按序连续编排。"))
par(first-line-indent: 2em, text(font: fsong, size: 12pt, "3正文插图、表格中的文字字号均为5号。"))
pagebreak()
set page(
margin: (left: 30mm, right: 30mm, top: 30mm, bottom: 30mm),
numbering: "1",
number-align: center,
)
set heading(numbering: "1.1")
// set text(font: hei, lang: "zh")
show heading: it => box(width: 100%)[
#v(0.50em)
#set text(font: hei)
#counter(heading).display()
// #h(0.5em)
#it.body
]
// Main body.
set par(justify: true)
body
}
#let para(t) = par(first-line-indent: 2em, text(font: song, size: 10.5pt, t))

File diff suppressed because one or more lines are too long

430
bayesian/main.typ Normal file → Executable file
View File

@ -1,289 +1,177 @@
#import "@preview/cetz:0.3.3"
#set text(font: ("Noto Sans CJK SC", "Noto Serif CJK SC"), lang: "zh")
#set page(paper: "a4", margin: (x: 2cm, y: 2cm))
#set heading(numbering: "1.")
#let answer(body) = block(
fill: luma(240),
stroke: (left: 2pt + blue),
inset: 10pt,
radius: 2pt,
width: 100%,
body
#import "labtemplate.typ": *
#show: nudtlabpaper.with(
author: "程景愉",
id: "202302723005",
title: "贝叶斯网络编程实验",
training_type: "普通本科生",
grade: "2023级",
major: "网络工程",
department: "计算机学院",
advisor: "祝恩",
jobtitle: "教授",
lab: "306-707",
date: "2025.12.31",
header_str: "贝叶斯网络编程实验报告",
simple_cover: true,
)
#align(center)[
#text(size: 18pt, weight: "bold")[第13-14章 概率与贝叶斯网络 习题解答]
#v(1em)
// *生成时间:* #datetime.today().display()
#set page(header: [
#set par(spacing: 6pt)
#align(center)[#text(size: 11pt)[人工智能实验报告]]
#v(-0.3em)
#line(length: 100%, stroke: (thickness: 1pt))
],)
#show heading: it => if it.level == 1 [
#v(1em)
#set text(font: hei, size: 16pt)
#it.body
#v(0.5em)
] else [
#v(0.8em)
#set text(font: "New Computer Modern", weight: "bold", style: "italic")
#it.body
#v(0.5em)
]
= 题目 1
*题意:* 已知 $P(a) = 0.3$, $P(b | a) = 0.2$, $P(c | a) = 0.5$。比较 $P(a and b)$ $P(a and c)$
#set heading(numbering: none)
#answer[
根据乘法公式 $P(x and y) = P(x)P(y|x)$
$ P(a and b) &= P(a) dot P(b | a) = 0.3 times 0.2 = 0.06 \
P(a and c) &= P(a) dot P(c | a) = 0.3 times 0.5 = 0.15 $
因为 $0.06 < 0.15$,所以 *$P(a and b) < P(a and c)$*
*答案B*
#outline(title: "目录",depth: 2, indent: 1em)
#set enum(indent: 0.5em,body-indent: 0.5em,)
#pagebreak()
= 实验介绍
#para[
本次实验旨在实现并比较两种贝叶斯网络近似推理算法拒绝采样Rejection Sampling和似然加权Likelihood Weighting
实验使用的贝叶斯网络模型包含四个布尔变量Cloudy (C), Sprinkler (S), Rain (R), WetGrass (W)。
网络结构为 $C \to S, C \to R, S \to W, R \to W$
实验目标是根据给定的条件概率表CPTs在已知证据 $S=T$ $W=T$ 的情况下,估计 $R=T$ 的后验概率 $P(R=T | S=T, W=T)$
]
= 题目 2
*题意:* $P(a or b)=0.7$, $P(a)=0.4$, $P(b)=0.5$,求 $P(a and b)$
= 实验内容
#para[
实验主要包含以下内容:
]
+ 根据题目描述的贝叶斯网络结构和条件概率表,构建数据结构表示该网络。
+ 实现拒绝采样算法:从先验分布中采样,拒绝与证据不一致的样本,利用保留样本中查询变量的频率作为后验概率的估计。
+ 实现似然加权算法:固定证据变量的值,对非证据变量进行采样,并根据证据变量的条件概率计算样本权重,利用加权频率估计后验概率。
+ 比较两种算法在不同采样数量N=100, 1000, ...)下的估计结果与真实值的偏差,分析算法收敛性。
#answer[
根据概率加法公式(容斥原理):
$ P(a or b) = P(a) + P(b) - P(a and b) $
代入已知数值:
$ 0.7 = 0.4 + 0.5 - P(a and b) \
P(a and b) = 0.9 - 0.7 = 0.2 $
*答案0.2*
= 实验情况
+ 使用 Python 语言实现算法。
+ 代码需清晰易读,包含必要的注释。
+ 计算并输出 $P(R=T | S=T, W=T)$ 的精确值以便对比。
+ 撰写实验报告,展示核心代码和实验结果。
= 实验步骤与实现
== 网络定义与概率表
首先定义网络的条件概率表CPTs
```python
# CPTs
P_C = {True: 0.5, False: 0.5}
# P(S | C)
P_S_given_C = {
True: {True: 0.10, False: 0.90}, # C=T
False: {True: 0.50, False: 0.50} # C=F
}
# P(R | C)
P_R_given_C = {
True: {True: 0.80, False: 0.20}, # C=T
False: {True: 0.20, False: 0.80} # C=F
}
# P(W | S, R)
P_W_given_SR = {
(True, True): {True: 0.99, False: 0.01},
(True, False): {True: 0.90, False: 0.10},
(False, True): {True: 0.90, False: 0.10},
(False, False): {True: 0.00, False: 1.00}
}
```
== 拒绝采样 (Rejection Sampling)
拒绝采样通过生成先验分布的样本,并丢弃那些与证据不符的样本来工作。
```python
def rejection_sampling(query_var, query_val, evidence, num_samples):
consistent_count = 0
query_match_count = 0
for _ in range(num_samples):
sample = get_prior_sample() # 从联合分布采样
# 检查样本是否与证据一致
is_consistent = True
for var, val in evidence.items():
if sample[var] != val:
is_consistent = False
break
if is_consistent:
consistent_count += 1
if sample[query_var] == query_val:
query_match_count += 1
if consistent_count == 0: return 0.0
return query_match_count / consistent_count
```
== 似然加权 (Likelihood Weighting)
似然加权强制证据变量取观测值,并将样本权重设为证据变量在其父节点给定情况下的似然概率乘积。
```python
def likelihood_weighting(query_var, query_val, evidence, num_samples):
weighted_counts = {True: 0.0, False: 0.0}
for _ in range(num_samples):
weight = 1.0
sample = {}
# 以 C, S, R, W 的拓扑顺序采样/赋值
# 若变量在证据中,则赋值为证据值并更新权重
# 若变量不在证据中,则根据父节点采样
# (代码细节略,参见附件源程序)
# ...
# 累加权重
weighted_counts[sample[query_var]] += weight
total_weight = sum(weighted_counts.values())
if total_weight == 0: return 0.0
return weighted_counts[query_val] / total_weight
```
= 实验结果
#para[
首先通过精确计算(枚举联合概率分布)得到理论真实值:
$P(R=T | S=T, W=T) approx 0.320388$
]
= 题目 3
*数据:* 全联合概率分布表如下Cavity, Toothache, Catch
#para[
下表展示了在不同采样数量 $N$ 下,两种算法的估计结果
]
#table(
columns: (auto, auto, auto, auto, auto),
inset: 8pt,
columns: (auto, auto, auto),
inset: 10pt,
align: center,
[], [T, Catch], [T, $not$ Catch], [$not$ T, Catch], [$not$ T, $not$ Catch],
[Cavity], [0.108], [0.012], [0.072], [0.008],
[$not$ Cavity], [0.016], [0.064], [0.144], [0.576]
[*样本数量 N*], [*拒绝采样结果*], [*似然加权结果*],
[100], [0.480000], [0.377902],
[1000], [0.353741], [0.311148],
[10000], [0.320734], [0.317552],
[100000], [0.318791], [0.321722],
[1000000], [0.319916], [0.319471],
)
#answer[
*1. 计算 $P("Toothache" or not "Cavity")$*
利用补集思想:$P(A) = 1 - P(not A)$
事件的补集是 $not "Toothache" and "Cavity"$
对应表格中的项为:(Cavity, $not$ T, Catch) (Cavity, $not$ T, $not$ Catch)。
$ P(not T and "Cav") = 0.072 + 0.008 = 0.080 $
$ P(T or not "Cav") = 1 - 0.080 = 0.92 $
= 实验总结
*2. 计算 $P(not "toothache" or "catch")$*
补集是 $"toothache" and not "catch"$
对应表格列为 (T, $not$ Catch),即第 2 列。
$ P(T and not "Catch") = 0.012 ("Cav") + 0.064 (not "Cav") = 0.076 $
$ P(not T or "Catch") = 1 - 0.076 = 0.924 $
+ *收敛性*:从实验结果可以看出,随着采样数量 $N$ 的增加,拒绝采样和似然加权算法的结果都逐渐收敛于真实值 $0.320388$
*3. 计算 $P("Toothache" or not "Cavity" | not "catch")$ 和 $P(not "catch" | "Toothache" or not "Cavity")$*
$A = "Toothache" or not "Cavity"$, $B = not "catch"$
- *计算 $P(B)$*: Sum of all $not$ Catch columns (Col 2, Col 4).
$P(B) = (0.012 + 0.064) + (0.008 + 0.576) = 0.076 + 0.584 = 0.66$
- *计算 $P(A and B)$*: $not$ Catch 列中满足 $T or not "Cav"$ 的项。
- (Cav, T, $not$ C): 0.012 (满足 T)
- ($not$ Cav, T, $not$ C): 0.064 (满足 T)
- ($not$ Cav, $not$ T, $not$ C): 0.576 (满足 $not$ Cav)
- (Cav, $not$ T, $not$ C): 0.008 (不满足既无T也无$not$Cav)
Sum $= 0.012 + 0.064 + 0.576 = 0.652$
结果 1: $P(A | B) = 0.652 / 0.66 approx 0.9879$
结果 2: $P(B | A) = P(A and B) / P(A) = 0.652 / 0.92 approx 0.7087$ (其中 P(A) 来自第1小问)
+ *算法比较*
- *拒绝采样*:实现简单,直接利用先验分布采样。但在证据概率较低时(本例中证据发生的概率约为 0.278,尚可),会拒绝大量样本,导致计算资源浪费。在样本量较小(如 N=100时波动较大。
- *似然加权*利用了证据信息所有生成的样本都是有效的权重不为0因此在相同采样数量下通常能提供比拒绝采样更稳定的估计尤其是当证据发生概率很低时优势更明显
*4. 判断 Cavity 与 Toothache 是否独立*
$ P("Cav") &= 0.108+0.012+0.072+0.008 = 0.2 \
P("Toothache") &= 0.108+0.012+0.016+0.064 = 0.2 \
P("Cav" and "T") &= 0.108 + 0.012 = 0.12 $
检验:$P("Cav") times P("T") = 0.2 times 0.2 = 0.04$
因为 $0.12 != 0.04$,所以两者 *不独立*
]
= 题目 4
*题意:* $X, Y$ 条件独立于 $Z$(即 $X perp Y | Z$$Y, W$ 条件独立于 $Z$(即 $Y perp W | Z$)。问 $X, W$ 是否条件独立于 $Z$
#answer[
*结论:不能。* 条件独立性不具备传递性。
*反例证明:*
假设 $Z$ 是一个公平的硬币投掷0 1
$X = Z$$X$ 完全依赖于 $Z$)。
$W = Z$$W$ 完全依赖于 $Z$)。
$Y$ 是一个与 $X, W, Z$ 都完全独立的随机变量(例如掷骰子)。
1. *检查 $X, Y$ 关于 $Z$ 的独立性*:给定 $Z$ $X$ 变为常数。常数与任何变量独立,故成立。
2. *检查 $Y, W$ 关于 $Z$ 的独立性*:同理,给定 $Z$$W$ 变为常数,故成立。
3. *检查 $X, W$ 关于 $Z$ 的独立性*
给定 $Z$$X$ $W$ 的值完全确定且相同(例如若 $Z=1$,则 $X=1, W=1$)。虽然在 $Z$ 固定的情况下它们的方差为0技术上可视作独立但如果我们考虑一种因果结构
$X$ $W$ 为同一变量的两个副本。显然它们是强相关的。
更直观的例子:$X$ $W$ 互为因果或由共同隐变量控制,而它们都与 $Y$ 独立。仅仅知道它们分别与 $Y$ 独立,无法切断 $X$ $W$ 之间的联系。
]
= 题目 5
*题意:* 罕见病检测。$P(D)=0.001$
检测A$P(+|D)=0.95, P(+|not D)=0.05$
检测B$P(+|D)=0.90, P(+|not D)=0.10$
#answer[
*a. 单次检测 A 为阳性,求 $P(D|A+)$*
使用贝叶斯公式:
$ P(D|A+) = (P(A+|D)P(D)) / P(A+) $
$ P(A+) &= P(A+|D)P(D) + P(A+|not D)P(not D) \
&= 0.95 times 0.001 + 0.05 times 0.999 \
&= 0.00095 + 0.04995 = 0.0509 $
$ P(D|A+) &= 0.00095 / 0.0509 approx 0.0187 (1.87%) $
*b. 两次检测 A 和 B 均为阳性,求 $P(D|A+, B+)$*
由于检测独立Naive Bayes 假设):
$ P(A+, B+ | D) = 0.95 times 0.90 = 0.855 $
$ P(A+, B+ | not D) = 0.05 times 0.10 = 0.005 $
$ P(D | A+, B+) &= (P(A+, B+ | D)P(D)) / (P(A+, B+ | D)P(D) + P(A+, B+ | not D)P(not D)) \
&= (0.855 times 0.001) / (0.855 times 0.001 + 0.005 times 0.999) \
&= 0.000855 / (0.000855 + 0.004995) \
&= 0.000855 / 0.00585 approx 0.1462 (14.62%) $
*c. 解释*
联合检测通过引入第二次独立测试,极大地降低了*假阳性率*(从 0.05 降至 $0.05 times 0.10 = 0.005$)。虽然真阳性率也略有下降,但分母中占主导地位的假阳性项(由 $P(not D)$ 权重放大)被大幅削减,从而显著提升了后验概率。
]
= 题目 6
*场景:* 骑车(B) 取决于 天气(W) 熬夜(S)。
$P(W="Sun")=0.7, P(S="Yes")=0.4$
CPT 已知。
#answer[
*a. 贝叶斯网络与 CPT*
结构:$W -> B <- S$ (V-structure)
#cetz.canvas({
import cetz.draw: *
let r = 0.8
// Nodes
circle((0, 0), radius: r, name: "B")
content("B", "B (骑车)")
circle((-2, 3), radius: r, name: "W")
content("W", "W (天气)")
circle((2, 3), radius: r, name: "S")
content("S", "S (熬夜)")
// Edges
line("W", "B", mark: (end: ">"))
line("S", "B", mark: (end: ">"))
})
*条件概率表 (CPT) for B:*
#table(
columns: 3,
align: center,
[W (天气)], [S (熬夜)], [P(B=是 | W, S)],
[晴 (Sun)], [否 (No)], [0.9],
[晴 (Sun)], [是 (Yes)], [0.6],
[雨 (Rain)], [否 (No)], [0.2],
[雨 (Rain)], [是 (Yes)], [0.1]
)
*b. 推理:已知骑车(B=Yes),求天气概率*
我们需要计算 $P(W | B="Yes")$。根据贝叶斯法则:$P(W|B) = P(B|W)P(W) / P(B)$。
首先计算边缘概率 $P(B="Yes")$。
$ P(B=y) = sum_(w, s) P(B=y|w,s)P(w)P(s) $
因 W 和 S 独立,联合概率直接相乘。
1. $W="Sun", S="No"$: $0.9 times 0.7 times 0.6 = 0.378$
2. $W="Sun", S="Yes"$: $0.6 times 0.7 times 0.4 = 0.168$
3. $W="Rain", S="No"$: $0.2 times 0.3 times 0.6 = 0.036$
4. $W="Rain", S="Yes"$: $0.1 times 0.3 times 0.4 = 0.012$
$ P(B="Yes") = 0.378 + 0.168 + 0.036 + 0.012 = 0.594 $
计算 $P(W="Sun" | B="Yes")$:
分子为 W=Sun 的所有情况之和项1 + 项2
$ P(B=y, W="Sun") = 0.378 + 0.168 = 0.546 $
$ P(W="Sun" | B="Yes") = 0.546 / 0.594 approx 0.919 $
同理,$P(W="Rain" | B="Yes") = (0.036 + 0.012) / 0.594 approx 0.081$。
*结论:这天最可能是晴天。*
]
= 题目 7
*智能健康助手:* 变量 S(吸烟), G(基因), L(肺癌), C(咳嗽), X(胸片)。
关系:$S->L, G->L, S->C, L->C, L->X$。
#answer[
*问题 1贝叶斯网络图*
#align(center)[
#cetz.canvas({
import cetz.draw: *
// Manually positioning nodes for clarity
let r = 0.5
circle((0, 0), radius: r, name: "L")
content("L", "L")
circle((-2, 2), radius: r, name: "S")
content("S", "S")
circle((2, 2), radius: r, name: "G")
content("G", "G")
circle((-1, -2), radius: r, name: "C")
content("C", "C")
circle((1, -2), radius: r, name: "X")
content("X", "X")
line("S", "L", mark: (end: ">"))
line("G", "L", mark: (end: ">"))
line("L", "X", mark: (end: ">"))
line("L", "C", mark: (end: ">"))
// S -> C 直接边
line("S", "C", mark: (end: ">"))
})
]
*问题 2概率推理 $P(L="Yes" | C="No", X="Yes")$*
$alpha$ 为归一化常数。我们需要计算 $P(L=y, C=n, X=y)$ $P(L=n, C=n, X=y)$
公式分解:$P(S,G,L,C,X) = P(S)P(G)P(L|S,G)P(C|L,S)P(X|L)$
求和消除 S, G
$ P(L, C, X) = P(X|L) sum_S sum_G P(C|L,S) P(L|S,G) P(S) P(G) $
*Case 1: L = Yes* (且 $C=n, X=y$)
因子 $P(X=y|L=y) = 0.9$
内部求和 $Sigma_(L=y)$:
- $S=y, G=h$: $P(C=n|L=y,S=y)P(L=y|S=y,G=h)P(S=y)P(G=h) = 0.2 times 0.6 times 0.3 times 0.2 = 0.0072$
- $S=y, G=l$: $0.2 times 0.3 times 0.3 times 0.8 = 0.0144$
- $S=n, G=h$: $P(C=n|L=y,S=n)P(L=y|S=n,G=h)P(S=n)P(G=h) = 0.4 times 0.4 times 0.7 times 0.2 = 0.0224$
- $S=n, G=l$: $0.4 times 0.1 times 0.7 times 0.8 = 0.0224$
$Sigma_(L=y) = 0.0072 + 0.0144 + 0.0224 + 0.0224 = 0.0664$
$P(L=y, C=n, X=y) = 0.9 times 0.0664 = 0.05976$
*Case 2: L = No* (且 $C=n, X=y$)
因子 $P(X=y|L=n) = 0.1$
内部求和 $Sigma_(L=n)$:
- $S=y, G=h$: $P(C=n|L=n,S=y)P(L=n|S=y,G=h)P(S=y)P(G=h) = 0.7 times 0.4 times 0.3 times 0.2 = 0.0168$
- $S=y, G=l$: $0.7 times 0.7 times 0.3 times 0.8 = 0.1176$
- $S=n, G=h$: $P(C=n|L=n,S=n)P(L=n|S=n,G=h)P(S=n)P(G=h) = 0.9 times 0.6 times 0.7 times 0.2 = 0.0756$
- $S=n, G=l$: $0.9 times 0.9 times 0.7 times 0.8 = 0.4536$
$Sigma_(L=n) = 0.0168 + 0.1176 + 0.0756 + 0.4536 = 0.6636$
$P(L=n, C=n, X=y) = 0.1 times 0.6636 = 0.06636$
*最终归一化:*
$ P(L="Yes" | ...) &= 0.05976 / (0.05976 + 0.06636) \
&= 0.05976 / 0.12612 approx 0.4738 $
*答案47.38%*
]
+ *结论*:两种算法均能有效进行近似推理。对于本实验中的简单网络和非极端概率证据,两者在 $N=10000$ 以上时均能给出较好的估计结果。

34
bayesian/task.txt Normal file
View File

@ -0,0 +1,34 @@
作业二:实现贝叶斯网络近似推理算法
(一)问题描述
实现两种基本的近似推理算法——拒绝采样和似然加权,并在一个简单的
贝叶斯网络PPT 示例)上进行应用和比较。
网络结构图:
C -> S
C -> R
S -> W
R -> W
变量解释:
C(Cloudy): 是否多云 (Boolean)
S(Sprinkler): 洒水器是否开启 (Boolean)
R(Rain): 是否下雨 (Boolean)
W(WetGrass): 草坪是否湿润 (Boolean)
条件概率表 (CPTs):
P(C=T) = 0.5
P(S | C):
P(S=T | C=T) = 0.10
P(S=T | C=F) = 0.50
P(R | C):
P(R=T | C=T) = 0.80
P(R=T | C=F) = 0.20
P(W | S, R):
P(W=T | S=T, R=T) = 0.99
P(W=T | S=T, R=F) = 0.90
P(W=T | S=F, R=T) = 0.90
P(W=T | S=F, R=F) = 0.00
(二) 任务要求
实现拒绝采样算法和似然加权算法,算法需要能够估计条件概率 P(X | e)
其中 X 是查询变量e 是证据。使用你实现的两种算法估计 P(R | S=T,
W=T)。
要求撰写实验报告,提供源程序。

Binary file not shown.