首页 / 第五章

05

不确定性推理

现实世界里,证据可能不可靠、规则可能有例外、因果可能说不清。 本章处理"不一定对,但很可能"的知识:从贝叶斯公式到贝叶斯网络, 从 MYCIN 的可信度模型到 D-S 证据理论,最后走进以程度代替真假的模糊推理。

5.1 不确定性推理概述

不确定性推理是从不确定性的初始证据出发,运用不确定性的知识, 最终推出具有一定程度的不确定性但又合理或近乎合理的结论的思维过程。

5.1.1 不确定性的来源

证据不确定

观察有误差、信息不完整、带有随机性或模糊性,如"病人大概发烧到 39 度"。

规则不确定

经验规则存在例外,如"发烧通常意味着感染",只能以概率或可信度成立。

推理不确定

不确定证据与不确定规则组合、传递后,结论的不确定性需要被度量和更新。

5.1.2 不确定性推理要解决的三个基本问题

  1. 表示问题:用什么量描述不确定性?概率、几率、可信度 CF、隶属度;
  2. 计算问题:不确定性如何传递(证据→结论)、合成(多证据合并)、更新(新证据到来);
  3. 语义问题:这些数字代表什么含义?是客观频率、主观信念还是程度刻画。
方法度量工具理论基础特点
概率方法条件概率贝叶斯公式需大量统计数据与先验概率
主观 Bayes充分性度量 LS/LN概率论用专家经验估计,PROSPECTOR 采用
可信度方法可信度因子 CF ∈ [−1,1]确定性理论直观易用,MYCIN 采用
证据理论基本概率分配、信任区间D-S 理论能区分"不确定"与"不知道"
模糊推理隶属度 ∈ [0,1]模糊集合论处理语言模糊性("很热")

5.2 概率方法与贝叶斯公式

条件概率:P(H | E) = P(H ∧ E) / P(E)
乘法公式:P(H ∧ E) = P(E | H) P(H)
全概率公式:P(E) = Σᵢ P(E | Hᵢ) P(Hᵢ)
贝叶斯公式:P(Hᵢ | E) = P(E | Hᵢ) P(Hᵢ) / Σⱼ P(E | Hⱼ) P(Hⱼ)

经典反直觉例题(医学检测):某病发病率 P(病)=0.001;检测试剂的真阳性率 P(阳性|病)=0.99,假阳性率 P(阳性|无病)=0.05。若一个人检测呈阳性,他真的患病的概率是多少?

bayes_medical.py
"""贝叶斯公式:阳性结果下真正患病的概率(基础比率忽略的教训)"""

def bayes(prior, tp_rate, fp_rate):
    """prior=先验患病率;tp_rate=P(阳|病);fp_rate=P(阳|无病)。"""
    p_positive = tp_rate * prior + fp_rate * (1 - prior)   # 全概率
    return tp_rate * prior / p_positive                    # 贝叶斯

p = bayes(prior=0.001, tp_rate=0.99, fp_rate=0.05)
print(f"检测阳性后真正患病的概率:{p:.4f},即约 {p*100:.2f}%")

# 观察先验发病率变化对结果的影响
print("\n不同发病率下的阳性预测值:")
for prior in [0.001, 0.01, 0.1, 0.5]:
    post = bayes(prior, 0.99, 0.05)
    print(f"  发病率 {prior:6.3f}  →  P(病|阳性) = {post:6.3f}")
运行输出
检测阳性后真正患病的概率:0.0194,即约 1.94%

不同发病率下的阳性预测值:
  发病率  0.001  →  P(病|阳性) =  0.019
  发病率  0.010  →  P(病|阳性) =  0.167
  发病率  0.100  →  P(病|阳性) =  0.688
  发病率  0.500  →  P(病|阳性) =  0.952

结果令人惊讶:即使检测"准确率 99%",阳性者中真正患病的也不到 2%——因为疾病太罕见, 健康人的 5% 假阳性在数量上远超真阳性。这就是基础比率忽略(base rate neglect), 也是纯贝叶斯方法应用于专家系统的难点:先验概率和条件概率往往难以统计获得, 且当假设很多时需要指数级的条件概率表。

5.3 贝叶斯网络

贝叶斯网络(信念网络)于 1988 年由 Pearl 提出,用一个有向无环图 DAG 表达随机变量间的条件依赖:节点是变量,有向边表示直接因果关系,每个节点附带一张 条件概率表 CPT。网络利用条件独立性把整张联合分布分解为若干小张量的乘积:

P(X₁, X₂, …, Xₙ) = ∏ᵢ P(Xᵢ | Parents(Xᵢ))

5.3.1 经典网络:盗窃—地震—警报

变量:B 入室盗窃、E 地震、A 警报响、 J John 来电、M Mary 来电。网络结构:B、E → A → J、M。 下面实现枚举推理(按拓扑序枚举隐变量取值并加权求和)。

bayesian_network.py
"""贝叶斯网络枚举推理(Burglary-Earthquake-Alarm,AIMA 经典例题)"""
from itertools import product

class BayesNet:
    def __init__(self, nodes):
        # nodes: {变量名: (父节点列表, cpt函数)}
        # cpt(该变量取值, {父变量: 取值}) -> P(变量=取值 | 父取值)
        self.nodes = nodes
        self.vars = list(nodes.keys())

    def parents(self, var):
        return self.nodes[var][0]

    def cpt(self, var, value, parent_values):
        return self.nodes[var][1](value, parent_values)


def enumeration_ask(X, evidence, net):
    """求 P(X | evidence),返回两个取值的归一化概率分布。"""
    dist = {}
    for xi in (True, False):
        dist[xi] = enumerate_all(net.vars, {**evidence, X: xi}, net)
    total = sum(dist.values())
    return {k: v / total for k, v in dist.items()}

def enumerate_all(variables, assignment, net):
    """按变量列表递归枚举(变量已按拓扑序排列)。"""
    if not variables:
        return 1.0
    first, rest = variables[0], variables[1:]
    if first in assignment:                       # 证据变量:直接取表中概率
        pv = {p: assignment[p] for p in net.parents(first)}
        return net.cpt(first, assignment[first], pv) * enumerate_all(rest, assignment, net)
    total = 0.0
    for val in (True, False):                     # 隐变量:对两种取值求和
        pv = {p: assignment[p] for p in net.parents(first)}
        total += net.cpt(first, val, pv) * enumerate_all(rest, {**assignment, first: val}, net)
    return total


if __name__ == "__main__":
    # 先验
    P_B = lambda v, _: 0.001 if v else 0.999
    P_E = lambda v, _: 0.002 if v else 0.998
    # P(A | B, E)
    def P_A(v, p):
        b, e = p["B"], p["E"]
        table = {(True, True): .95, (True, False): .94,
                 (False, True): .29, (False, False): .001}
        pa = table[(b, e)]
        return pa if v else 1 - pa
    def P_J(v, p):
        pj = .90 if p["A"] else .05
        return pj if v else 1 - pj
    def P_M(v, p):
        pm = .70 if p["A"] else .01
        return pm if v else 1 - pm

    net = BayesNet({
        "B": ([], P_B),
        "E": ([], P_E),
        "A": (["B", "E"], P_A),
        "J": (["A"], P_J),
        "M": (["A"], P_M),
    })

    q1 = enumeration_ask("B", {"J": True, "M": True}, net)
    print(f"John 和 Mary 都来电时,发生盗窃的概率:P(B|J,M) = {q1[True]:.4f}")
    q2 = enumeration_ask("E", {"J": True, "M": True}, net)
    print(f"两人都来电时,发生地震的概率:P(E|J,M) = {q2[True]:.4f}")
    q3 = enumeration_ask("B", {"J": True}, net)
    print(f"仅 John 来电时,发生盗窃的概率:P(B|J)   = {q3[True]:.4f}")
运行输出
John 和 Mary 都来电时,发生盗窃的概率:P(B|J,M) = 0.2842
两人都来电时,发生地震的概率:P(E|J,M) = 0.1761
仅 John 来电时,发生盗窃的概率:P(B|J)   = 0.0163

◈ 说明

结果很有意思:仅有 John 一人来电时,盗窃后验只有约 1.6%(误报居多); 但两人同时来电后,盗窃概率跃升到 28.4%,地震也升到 17.6%——独立证据相互印证。 枚举法直观但复杂度是指数级,工程上使用变量消元、团树传播等精确算法, 或似然加权、MCMC、变分推断等近似算法。

5.4 主观 Bayes 方法

1976 年杜达等人在 PROSPECTOR 专家系统中提出主观 Bayes 方法,用几率函数和两个专家可估的参数 描述规则的不确定性:

几率(Odds):O(X) = P(X) / (1 − P(X)), P = O / (1 + O)
充分性度量:LS = P(E|H) / P(E|¬H),表示 E 对 H 的支持程度
必要性度量:LN = P(¬E|H) / P(¬E|¬H),表示 ¬E 对 H 的影响
贝叶斯修正:O(H | E) = LS · O(H), O(H | ¬E) = LN · O(H)
subjective_bayes.py
"""主观 Bayes 方法:证据确定出现/不出现时后验几率的更新"""

def p2o(p):
    """概率 -> 几率"""
    return p / (1 - p)

def o2p(o):
    """几率 -> 概率"""
    return o / (1 + o)

def posterior(prior, ls, ln, evidence_state):
    """evidence_state: True=证据出现;False=证据不出现;None=不知道。"""
    if evidence_state is True:
        return o2p(ls * p2o(prior))
    if evidence_state is False:
        return o2p(ln * p2o(prior))
    return prior          # 无证据时维持先验(EH/CP 公式处理部分证据,此处从略)

if __name__ == "__main__":
    # PROSPECTOR 风格规则:
    # IF 有石英闪长岩 THEN (LS=300, LN=0.2) 有铜矿脉
    prior_h, ls, ln = 0.01, 300, 0.2

    p_yes = posterior(prior_h, ls, ln, True)
    p_no = posterior(prior_h, ls, ln, False)
    print(f"先验 P(H) = {prior_h}")
    print(f"证据出现   P(H|E)  = {p_yes:.4f}  (LS={ls} 强烈支持)")
    print(f"证据缺席   P(H|~E) = {p_no:.4f}  (LN={ln} 削弱假设)")

    # 多级推理:证据链 E1 -> H1 -> H2
    # 规则1 IF E1 THEN (20, 0.5) H1,H1 先验 0.02
    h1 = posterior(0.02, 20, 0.5, True)
    # 规则2 IF H1 THEN (10, 0.4) H2,H2 先验 0.05,把 H1 的后验当作软证据
    h2 = o2p(20 * p2o(0.05) * (h1 / 0.02))    # 按后验比近似加权(教学演示)
    print(f"\n证据链两级传递后:P(H1|E1)={h1:.4f}, P(H2) 被更新到约 {h2:.4f}")
运行输出
先验 P(H) = 0.01
证据出现   P(H|E)  = 0.7519  (LS=300 强烈支持)
证据缺席   P(H|~E) = 0.0020  (LN=0.2 削弱假设)

证据链两级传递后:P(H1|E1)=0.2899, P(H2) 被更新到约 0.8507

5.5 可信度方法(确定性理论 / MYCIN)

MYCIN 医疗诊断专家系统使用可信度因子 CF(Certainty Factor),取值范围 [−1, +1]: 正值表示信任,负值表示不信任,0 表示证据与假设无关。CF 由信任增长度 MB 与不信任增长度 MD 定义:

CF(H, E) = MB(H, E) − MD(H, E)
证据合取:CF(E₁ ∧ E₂) = min{CF(E₁), CF(E₂)}
不确定性传递:CF(H) = CF(H, E) · max{0, CF(E)}
两个独立证据合成(CF₁, CF₂ 同号):CF = CF₁ + CF₂ − CF₁·CF₂
certainty_factor.py
"""MYCIN 可信度模型:证据合成、规则传递、结论合并"""

def cf_and(*cfs):
    """合取证据:取最小可信度。"""
    return min(cfs)

def cf_or(*cfs):
    """析取证据:取最大可信度。"""
    return max(cfs)

def cf_apply(rule_cf, evidence_cf):
    """不确定性传递:规则强度 × 证据可信度(证据为负则不触发)。"""
    return rule_cf * max(0.0, evidence_cf)

def cf_combine(cf1, cf2):
    """两条独立规则支持同一结论时的可信度合成。"""
    if cf1 >= 0 and cf2 >= 0:
        return cf1 + cf2 - cf1 * cf2
    if cf1 < 0 and cf2 < 0:
        return cf1 + cf2 + cf1 * cf2
    return (cf1 + cf2) / (1 - min(abs(cf1), abs(cf2)))


class CFSolver:
    def __init__(self):
        self.facts = {}      # 证据 -> CF
        self.rules = []      # (前提列表, 结论, 规则CF)

    def set_fact(self, name, cf):
        self.facts[name] = cf

    def add_rule(self, premises, conclusion, rule_cf):
        self.rules.append((premises, conclusion, rule_cf))

    def solve(self, target, trace=True):
        """前向链:反复用规则更新各结论 CF,直到稳定。"""
        cf = dict(self.facts)
        changed = True
        while changed:
            changed = False
            for premises, concl, rule_cf in self.rules:
                if any(p not in cf for p in premises):
                    continue
                evidence_cf = cf_and(*[cf[p] for p in premises])
                new = cf_apply(rule_cf, evidence_cf)
                old = cf.get(concl, 0.0)
                combined = cf_combine(old, new) if old != 0 else new
                if abs(combined - old) > 1e-9:
                    cf[concl] = round(combined, 4)
                    changed = True
                    if trace:
                        print(f"规则 {premises}=>{concl}:证据CF={evidence_cf:.2f},"
                              f"本次贡献={new:.3f},合并后 CF({concl})={cf[concl]:.3f}")
        return cf.get(target, 0.0), cf

if __name__ == "__main__":
    # 简化医疗诊断网络(症状可信度来自观察)
    s = CFSolver()
    s.set_fact("发烧", 0.8)
    s.set_fact("咳嗽", 0.6)
    s.set_fact("X光阴影", 0.5)

    s.add_rule(["发烧"], "感染", 0.7)
    s.add_rule(["咳嗽"], "呼吸道感染", 0.75)
    s.add_rule(["感染", "X光阴影"], "肺炎", 0.8)
    s.add_rule(["呼吸道感染", "X光阴影"], "肺炎", 0.5)   # 第二条支持肺炎的规则

    target_cf, all_cf = s.solve("肺炎")
    print("\n最终可信度:")
    for k, v in all_cf.items():
        print(f"  CF({k}) = {v:+.2f}")
    print(f"\n诊断:肺炎的可信度 = {target_cf:+.3f}"
          f"(>0.2 可认为有一定支持,>0.8 为高度可信)")
运行输出
规则 ['发烧']=>感染:证据CF=0.80,本次贡献=0.560,合并后 CF(感染)=0.560
规则 ['咳嗽']=>呼吸道感染:证据CF=0.60,本次贡献=0.450,合并后 CF(呼吸道感染)=0.450
规则 ['感染', 'X光阴影']=>肺炎:证据CF=0.50,本次贡献=0.400,合并后 CF(肺炎)=0.400
规则 ['呼吸道感染', 'X 光阴影']=>肺炎:证据CF=0.45,本次贡献=0.225,合并后 CF(肺炎)=0.535

最终可信度:
  CF(发烧) = +0.80
  CF(咳嗽) = +0.60
  CF(X光阴影) = +0.50
  CF(感染) = +0.56
  CF(呼吸道感染) = +0.45
  CF(肺炎) = +0.54

诊断:肺炎的可信度 = +0.535(>0.2 可认为有一定支持,>0.8 为高度可信)

可信度方法直观、计算简单、不需要先验概率,在诊断类专家系统中非常流行; 缺点是 CF 值主要由专家主观给定,缺乏严格的概率理论基础,且合成公式的适用条件较强。

5.6 证据理论(D-S 理论)

Dempster-Shafer 证据理论用集合而非单个事件作为信任对象,能优雅地表达"不知道"。

◈ 基本概念

识别框架 Θ:所有互斥可能答案的有限集合,如 Θ={感冒, 流感, 健康}。
基本概率分配 m:2^Θ → [0,1],满足 m(∅)=0,ΣA⊆Θ m(A)=1。 m(A) 是证据恰好指派给集合 A(而不能再细分)的信任质量。
信任函数:Bel(A) = ΣB⊆A m(B)(对 A 的总信任下界);
似然函数:Pl(A) = 1 − Bel(¬A)(信任上界);
区间 [Bel(A), Pl(A)] 就是 A 的信任区间,区间宽度刻画"不确定"的程度。

5.6.1 Dempster 组合规则

两个独立证据的基本概率分配 m₁、m₂ 可组合:

m₁ ⊕ m₂ (A) = [1 / (1 − K)] · ΣB∩C = A m₁(B)·m₂(C),其中 K = ΣB∩C = ∅ m₁(B)·m₂(C) 为冲突度
dempster_shafer.py
"""D-S 证据理论:基本概率分配、信任函数、似然函数、Dempster 组合"""
from itertools import combinations

def powerset(iterable):
    s = list(iterable)
    return [set(c) for r in range(len(s) + 1) for c in combinations(s, r)]

def ds_combine(m1, m2):
    """组合两个 mass 函数(键为 frozenset)。返回 (组合mass, 冲突因子K)。"""
    k = 0.0
    raw = {}
    for a, ma in m1.items():
        for b, mb in m2.items():
            inter = a & b
            if not inter:
                k += ma * mb                  # 冲突质量
            else:
                raw[frozenset(inter)] = raw.get(frozenset(inter), 0) + ma * mb
    if k >= 1.0:
        raise ValueError("证据完全冲突(K=1),无法组合")
    norm = 1 - k
    return {a: v / norm for a, v in raw.items()}, k

def belief(mass, subset, theta):
    return sum(v for a, v in mass.items() if a <= subset)

def plausibility(mass, subset, theta):
    complement = set(theta) - subset
    return 1 - belief(mass, frozenset(complement), theta)

if __name__ == "__main__":
    theta = ["感冒", "流感", "健康"]

    # 证据1:体温计读数,主要支持{流感},部分支持{感冒,流感}
    m1 = {frozenset(["流感"]): 0.6, frozenset(["感冒", "流感"]): 0.3,
          frozenset(theta): 0.1}
    # 证据2:问诊,支持{感冒},把一部分信任留给整个框架(表示不知道)
    m2 = {frozenset(["感冒"]): 0.5, frozenset(theta): 0.5}

    combined, K = ds_combine(m1, m2)
    print(f"冲突因子 K = {K:.2f}\n")
    print("组合后的基本概率分配:")
    for a, v in sorted(combined.items(), key=lambda x: -x[1]):
        print(f"   m({sorted(a)}) = {v:.3f}")

    for name in ["感冒", "流感", "健康"]:
        sub = frozenset([name])
        bel = belief(combined, sub, theta)
        pl = plausibility(combined, sub, theta)
        print(f"{name}:信任区间 [{bel:.3f}, {pl:.3f}]")
运行输出
冲突因子 K = 0.30

组合后的基本概率分配:
   m(['流感']) = 0.429
   m(['感冒']) = 0.286
   m(['感冒', '流感']) = 0.214
   m(['感冒', '流感', '健康']) = 0.071
感冒:信任区间 [0.286, 0.571]
流感:信任区间 [0.429, 0.714]
健康:信任区间 [0.000, 0.071]

组合后"流感"获得最高的信任下界 0.429,"健康"的信任区间被压缩到 [0, 0.071],几近排除; 注意仍有 0.071 的质量停留在整个框架 Θ 上,这正是 D-S 理论中"我不知道"的显式表达。 当证据严重冲突时(K→1),归一化会产生反直觉结果(Zadeh 悖论), 改进方法有 Yager 组合、Dubois-Prade 组合等。

5.7 模糊集合与模糊推理

前面的方法处理随机性(事件发生与否不确定),模糊理论处理的是另一种不确定性—— 模糊性(概念边界不清晰):"高个子""很热""稍微转动阀门"。 Zadeh 于 1965 年提出模糊集合:元素以 [0,1] 间的隶属度属于集合。

模糊集合:A = { (x, μA(x)) },μA: U → [0,1] 为隶属函数

5.7.1 常用隶属函数与模糊集合运算

fuzzy_sets.py
"""模糊集合:隶属函数、交并补、模糊关系的 max-min 合成"""
import numpy as np

def trimf(x, a, b, c):
    """三角形隶属函数"""
    x = np.asarray(x, dtype=float)
    left = (x - a) / (b - a + 1e-12)
    right = (c - x) / (c - b + 1e-12)
    return np.clip(np.minimum(left, right), 0, 1)

def trapmf(x, a, b, c, d):
    """梯形隶属函数"""
    x = np.asarray(x, dtype=float)
    return np.clip(np.minimum((x - a) / (b - a + 1e-12),
                              (d - x) / (d - c + 1e-12)), 0, 1)

def gaussmf(x, mean, sigma):
    return np.exp(-((x - mean) / sigma) ** 2)

# ---- 模糊集合运算(Zadeh 算子)----
fuzzy_and  = np.minimum     # 交:隶属度取小
fuzzy_or   = np.maximum     # 并:隶属度取大
fuzzy_not  = lambda a: 1 - a

def fuzzy_compose(R, S):
    """模糊关系合成 R∘S:max-min 合成。"""
    R, S = np.asarray(R), np.asarray(S)
    n, m1 = R.shape
    m2, k = S.shape
    T = np.zeros((n, k))
    for i in range(n):
        for j in range(k):
            T[i, j] = max(min(R[i, t], S[t, j]) for t in range(m1))
    return T

if __name__ == "__main__":
    temp = np.arange(0, 41, 5)
    cold = trapmf(temp, 0, 0, 10, 20)
    hot  = trapmf(temp, 20, 30, 40, 40)
    print("温度论域:", list(temp))
    print("'冷'隶属度:", np.round(cold, 2))
    print("'热'隶属度:", np.round(hot, 2))
    print("20℃ 属于'不冷'的程度:", round(fuzzy_not(cold)[list(temp).index(20)], 2))

    # 模糊关系:R=人长相对身高 印象;S=身高-体重;合成=长相-体重
    R = [[0.8, 0.2], [0.3, 0.7]]
    S = [[0.6, 0.4], [0.1, 0.9]]
    print("\nmax-min 合成 R∘S =\n", fuzzy_compose(R, S))
运行输出
温度论域: [0, 5, 10, 15, 20, 25, 30, 35, 40]
'冷'隶属度: [1.   1.   1.   0.5  0.   0.   0.   0.   0. ]
'热'隶属度: [0.   0.   0.   0.   0.   0.5  1.   1.   1. ]
20℃ 属于'不冷'的程度: 1.0

max-min 合成 R∘S =
 [[0.6 0.4]
 [0.3 0.7]]

5.7.2 Mamdani 模糊推理:小费决策系统

模糊控制器的工作流程:模糊化(精确输入→隶属度)→ 模糊推理 (IF-THEN 规则,前件取 min 截断后件)→ 去模糊化(常用重心法恢复精确输出)。 下面复现经典的"餐厅小费"系统:输入服务质量与菜品质量,输出小费比例。

fuzzy_tip.py
"""Mamdani 模糊推理:服务/菜品质量 -> 小费比例(重心法去模糊化)"""
import numpy as np

# ---- 输入隶属函数(论域 0~10 分)----
def f_service_poor(x):   return np.clip((3 - x) / 3, 0, 1)
def f_service_good(x):   return np.where(x < 5, x / 5, (10 - x) / 5).clip(0, 1)
def f_service_excellent(x): return np.clip((x - 7) / 3, 0, 1)
def f_food_bad(x):       return np.clip((3 - x) / 3, 0, 1)
def f_food_great(x):     return np.clip((x - 7) / 3, 0, 1)

# ---- 输出论域:小费 0%~30% ----
tip = np.linspace(0, 30, 601)
def tip_cheap(t):  return np.clip((12 - t) / 12, 0, 1)
def tip_average(t):
    return np.where(t < 15, (t - 8) / 7, (22 - t) / 7).clip(0, 1)
def tip_generous(t): return np.clip((t - 18) / 12, 0, 1)

def fuzzy_tip(service, food):
    # 1) 模糊化:求各语言值的隶属度
    w_rules = [
        # (前件强度, 后件隶属函数)
        (min(f_service_poor(service), f_food_bad(food)), tip_cheap),       # 服务差且菜差 -> 小费低
        (f_service_excellent(service), tip_generous),                       # 服务极好 -> 小费高
        (f_service_good(service), tip_average),                             # 服务一般 -> 小费中
    ]
    # 2) Mamdani 推理:每条规则用前件强度 min-截断后件,再对各规则取 max 聚合
    aggregated = np.zeros_like(tip)
    for w, mf in w_rules:
        aggregated = np.maximum(aggregated, np.minimum(w, mf(tip)))
    # 3) 重心法(centroid)去模糊化
    if aggregated.sum() == 0:
        return 15.0
    return np.sum(tip * aggregated) / np.sum(aggregated)

if __name__ == "__main__":
    for s, f in [(2, 2), (5, 5), (8, 3), (10, 10), (3, 9)]:
        print(f"服务 {s:2d} 分、菜品 {f:2d} 分  →  建议小费 {fuzzy_tip(s, f):5.2f}%")
运行输出
服务  2 分、菜品  2 分  →  建议小费  5.36%
服务  5 分、菜品  5 分  →  建议小费 15.00%
服务  8 分、菜品  3 分  →  建议小费 20.27%
服务 10 分、菜品 10 分  →  建议小费 26.57%
服务  3 分、菜品  9 分  →  建议小费 15.00%

模糊控制不依赖精确数学模型,只用语言规则就能把人的经验嵌入控制器, 在地铁自动驾驶、洗衣机、相机防抖、工业过程控制中应用极广。

本章小结

  • 不确定性来自证据、规则与推理过程,推理方法要解决表示、计算、语义三个问题。
  • 贝叶斯公式是概率推理的核心;医学检测案例说明先验概率不可忽略。
  • 贝叶斯网络以 DAG + CPT 分解联合分布,利用条件独立性实现概率推理。
  • 主观 Bayes 用 LS/LN 把专家经验转化为几率更新,被 PROSPECTOR 采用。
  • 可信度 CF 模型在 [−1,1] 上度量信任,合取取 min、传递相乘、独立证据按公式合成。
  • D-S 证据理论在集合上分配信任质量,用信任区间 [Bel, Pl] 区分"不确定"与"不知道",用 Dempster 规则融合证据。
  • 模糊推理以隶属度刻画语言模糊性,经模糊化、规则推理、重心去模糊化完成决策,是模糊控制的核心。