
简介这份基于互信息贝叶斯网络的交通事故严重程度分析文档面向交通安全研究者、交通运输管理从业者及数据分析学习者针对省际客运事故成因复杂、小样本数据难以建模等痛点提出以改进互信息方法构造先验网络、结合CACC离散算法与贝叶斯网络进行事故严重程度综合分析的完整技术路线可有效支撑事故致因识别与安全策略制定。文档以严谨的学术论文形式呈现包含引言、建模方法、模型验证及结论等内容其中对CACC数据离散化、k值交叉验证选取、互信息边定向策略、GTT算法结构学习等关键步骤均有公式推导与流程说明适合希望将机器学习方法应用于交通安全定量研究或撰写相关论文的读者参考。资源为1个docx文档压缩包大小约344KB目前已有96人学习内容完整、逻辑清晰是一份具有方法创新性和工程借鉴价值的研究资料。1. 省际客运事故数据为什么难建模省际客运事故数据有一个让所有做交通安全分析的人头疼的特点样本少、分布偏、字段杂。以上海市 2005—2019 年的省际客运事故数据为例原始记录 790 条清洗后只剩 741 条有效样本其中“受伤事故”512 条占近七成而“死亡事故”仅 103 条。用这种数据直接跑回归模型很容易被多数类带偏少数类几乎学不到规律。更麻烦的是事故严重程度与驾驶员、车辆、道路、环境之间的关系高度非线性传统 Logit 模型既难筛选特征又难以刻画交互效应。这篇文章要拆解的就是一套针对这类小样本、非线性、类别不平衡数据的完整建模方案用 CACC 有监督离散算法处理连续变量用改进互信息方法在数据中直接构造先验网络再交给贝叶斯网络做结构学习和参数学习最后用 ROC 曲线和留一法交叉验证评估泛化能力。整套流程在 Matlab R2020a 和 GeNIe 3.0 中实现从数据清洗到风险因素量化分析每一步都有明确的参数设置和可复现的操作命令。适合正在做交通事故致因分析、安全风险评估或者在小样本场景下用贝叶斯网络建模的工程师和数据科学家参考——这套方法的核心价值不在算法多新而在“小样本下怎么把先验知识交给模型”这个通用问题上给出了可操作的思路。2. CACC 离散算法处理分布不均的小样本数据原始数据里 14 个变量中有 2 个连续变量其余 12 个虽是离散变量但部分变量如年龄、驾龄的原始区间划分是人为给定的。直接用原始区间做贝叶斯网络学习可能因为区间边界与事故严重程度的真实分布不匹配而丢失信息。因此建模前必须做数据离散化而离散化的质量直接决定后续互信息计算和网络结构学习的准确性。2.1 为什么选 CACC 而不是等宽或 CAIM常见离散化方法有三种思路无监督的等宽等频离散、有监督的 CAIM/CDD 离散、以及本文使用的 CACC 离散。等宽离散不考虑类别标签分布容易把事故严重程度的边界切错CAIM 算法只关注类别与区间之间的依赖强度对样本分布不均匀的数据容易过拟合CACC 算法的评分函数综合考虑了所有样本的分布信息本质上是把“类-属性相依系数”作为评分标准在样本量只有 741 条的情况下能最大程度保留原始数据的知识结构。CACC 的核心公式是cacc sqrt(y / (y M))其中y M * [(sum(sum(q_ir^2 / (M_i * M_r)))) - 1] / log2(n)M 为样本总量n 为区间数q_ir 表示落在区间 [d(r-1), d(r)] 内的第 i 类样本数M_i 为第 i 类样本总数M_r 为区间内的样本总数。评分函数衡量的是“离散后区间与类别之间的依赖程度”——值越高说明这个切分方式越能区分不同类别。2.2 CACC 在 Matlab 中的实现步骤用 Matlab R2020a 实现 CACC 算法时建议按以下步骤组织代码。算法以“事故类型”作为监督变量最大区间数设为 5。% CACC 离散化核心逻辑 function cut_points cacc_discretize(data, labels, max_intervals) % data: 待离散的连续变量列向量 % labels: 监督变量事故类型列向量 % max_intervals: 最大区间数本例设为 5 M length(data); % 样本总量 S length(unique(labels)); % 类别数此处 S3 sorted_data sort(data); % 升序排列 % 初始化区间边界最小值到最大值 bounds [min(data), max(data)]; best_cacc -inf; cut_points []; % 迭代尝试不同切分点寻找使 cacc 最大的区间划分 for n 2:max_intervals % 计算所有相邻值的中点作为候选切分点 candidates (sorted_data(1:end-1) sorted_data(2:end)) / 2; % 去掉重复候选点 candidates unique(candidates); % 对每个候选切分点组合计算 CACC 值 % 实际实现中需要遍历所有组合此处简化为贪心策略 for i 1:length(candidates) temp_bounds sort([bounds, candidates(i)]); cacc_val compute_cacc(data, labels, temp_bounds, M, S); if cacc_val best_cacc best_cacc cacc_val; cut_points temp_bounds(2:end-1); % 内部切分点 end end end end function cacc compute_cacc(data, labels, bounds, M, S) % 根据当前区间边界计算 CACC 评分 n length(bounds) - 1; % 区间数 [~, ~, bin_idx] histcounts(data, bounds); % 构建列联表行是类别列是区间 contingency zeros(S, n); for i 1:S for r 1:n contingency(i, r) sum(labels i bin_idx r); end end % 计算行和列的总和 row_sums sum(contingency, 2); col_sums sum(contingency, 1); % 计算 y 值 y 0; for i 1:S for r 1:n if row_sums(i) 0 col_sums(r) 0 y y contingency(i, r)^2 / (row_sums(i) * col_sums(r)); end end end y M * (y - 1) / log2(n); % CACC 值 cacc sqrt(y / (y M)); end代码逻辑分成两层外层遍历候选切分点并迭代更新区间边界内层计算每个切分方案对应的 CACC 评分。这里的核心参数是max_intervals5即每个连续变量最多被切成 5 个区间——设置上限是为了避免区间过多导致每个区间内样本过少后续贝叶斯网络的参数学习会不稳定。2.3 离散结果的实际效果原始数据中的连续变量包括“年龄”“财产损失”加上部分原本区间划分不合理的离散变量共 7 个变量需要 CACC 处理。以“年龄”为例原始分布从 20 岁到 60 岁都有用 CACC 处理后得到 5 个区间0~27、28~47、48~51、52~54、54。这个划分很有意思——不是均匀切分而是根据事故严重程度的分布密度自适应调整边界。28~47 岁区间宽度最大因为这个年龄段驾驶员最多但事故严重程度分布相对均匀48~51 和 52~54 两个区间很窄说明这些年龄段的驾驶员事故严重程度有显著变化需要更细的切分粒度。“财产损失”被离散为 0~110、111~515.5、516.5~9185、9185 四个区间同样呈现出明显的不均匀特性。这就是 CACC 相比等宽离散的本质优势等宽离散会把 0~10000 的财产损失切成等宽的 5 段结果大量样本集中在第一个区间几乎没有区分度CACC 则根据“财产损失”与“事故类型”之间的依赖关系动态调整切分点让每个区间内的类别分布尽可能不同。提示CACC 的“最大区间数”需要根据样本量权衡。741 条样本、3 个类别时5 个区间已经接近上限如果样本量更大可以适当放宽到 7~10 个区间但区间数超过类别数的两倍后过拟合风险会显著上升。3. 基于互信息构造先验网络绕开专家知识的主观偏差贝叶斯网络结构学习有一个两难问题纯数据驱动score-based search在变量多时容易陷入局部最优纯专家知识驱动又引入主观偏差。本文的场景是 14 个变量、741 条样本搜索空间巨大必须用先验知识约束搜索方向。但项目组希望尽可能排除主观因素因此选择了互信息方法从数据中直接构造先验网络。3.1 互信息估计的改进KNN 思想与 k 值选取传统互信息计算需要估计变量的概率密度在小样本下偏差很大。本文采用基于 KNN 思想的互信息估计方法核心公式为I(X, Y) psi(k) - psi(mx 1) psi(my 1) psi(M)psi(x) 为 digamma 函数mx、my 分别为水平与垂直方向落入 k 邻域内的样本点数M 为样本总量。公式的本质是用每个样本点周围 k 个近邻的空间分布来近似估计熵值k 越小系统误差越小但统计误差越大k 越大统计误差越小但系统误差越大。关键问题在于 k 值怎么选。原论文没有用经验值而是用交叉验证确定最优 k。具体做法是将数据按 70%/30% 分为训练集和测试集对每个候选 k 值用训练集构造 k 邻域分类器再用测试集评估分类准确率选准确率最高的 k 值。% 交叉验证选取最佳 k 值 % 数据已经过 CACC 离散化处理 % X_train: 训练集特征矩阵 (m x n)X_test: 测试集特征矩阵 (k x n) % y_train: 训练集标签y_test: 测试集标签 k_values 5:2:35; % 候选 k 值范围 accuracies zeros(length(k_values), 1); for idx 1:length(k_values) k k_values(idx); predictions zeros(size(X_test, 1), 1); for i 1:size(X_test, 1) % 计算当前测试样本到所有训练样本的欧氏距离 distances sqrt(sum((X_train - X_test(i, :)).^2, 2)); % 按距离升序排列取前 k 个近邻 [~, sorted_idx] sort(distances); knn_idx sorted_idx(1:k); % 用 k 近邻的标签做多数投票 knn_labels y_train(knn_idx); predictions(i) mode(knn_labels); end accuracies(idx) sum(predictions y_test) / length(y_test); end % 找到准确率最高的 k 值 [~, best_idx] max(accuracies); best_k k_values(best_idx); fprintf(最优 k %d分类准确率 %.4f\n, best_k, accuracies(best_idx));这段代码的核心逻辑是对每个候选 k 值做一次完整的 KNN 分类测试。候选 k 值范围为 5 到 35步长 2最终选出的最优 k21。选 k21 意味着互信息估计时每个样本点要考察周围 21 个邻居的空间分布——这个值偏大说明数据噪声较多需要较大的邻域来平滑统计波动。3.2 互信息矩阵与变量关联度排序用最优 k 值计算 14 个变量两两之间的互信息得到一个 14x14 的对称矩阵。矩阵中每个元素表示两个变量之间的统计相关性值越大说明关联越强。从论文给出的互信息矩阵可以看到几个值得注意的结果“事故地点”与“事故类型”的互信息值为 10.78是所有变量中最高的“重伤人数”“死亡人数”“轻伤人数”三个结果变量两两之间互信息值也很高说明伤亡情况高度相关“天气”与“事故类型”的互信息值仅为 9.97在影响因素中垫底——这说明天气单独对事故严重程度的直接影响不如直觉上那么强而是需要与其他因素交互才起作用提取“事故类型”这一列按互信息值降序排列得到先验网络的初始节点序列。序列前 4 个是结果变量重伤人数、死亡人数、轻伤人数、财产损失第 5 位开始是影响因素变量。这个排序本身就有意义——它告诉我们哪些因素与事故严重程度的相关性最强可以作为后续因果分析的优先关注对象。3.3 阈值筛选与先验网络生成得到关联度序列后需要决定哪些变量与“事故类型”之间画有向边。直接用全部变量会引入噪声用太少则会丢失信息。论文采用阈值筛选法从 9.6 到 10.7以 0.1 为间隔设置了 12 个互信息阈值对每个阈值将大于该阈值的变量节点与结果变量之间连有向边构造一个先验网络。再加上“全连接”和“全不连接”两个对照组一共 14 个候选先验网络。这里有个容易被忽略的工程细节为什么是 9.6 到 10.7 这个范围观察表 2 的互信息矩阵可发现“事故类型”与其他变量的互信息值分布在 9.64 到 10.78 之间最大值 10.78 就是“事故地点”最小值 9.64 是“年龄”。这个范围刚好覆盖了全部相关变量的 MI 值区间阈值间隔 0.1 能保证足够的搜索粒度。对 14 个候选先验网络分别执行贝叶斯网络结构学习然后用留一法LOO交叉验证评估精度。留一法在样本量小于 1000 时比 k 折交叉验证更稳定——每次用 740 条样本训练、1 条样本验证循环 741 次虽然计算量大但每个样本都能被验证一次评估结果无偏。最终测试结果显示当连接阈值为 10.5 时网络最优。也就是说只有互信息值大于 10.5 的变量才与“事故类型”直接相连。回看表 3满足条件的变量包括重伤人数10.66、死亡人数10.65、轻伤人数10.40 剔除、财产损失9.94 剔除、事故地点10.78、号牌种类10.64、性别10.63、季节10.51、时间10.31 剔除。实际留下的直接连接是重伤人数、死亡人数、事故地点、号牌种类、性别、季节。这些变量就是先验网络中的直接父节点或直接子节点。% 根据互信息阈值筛选变量构造先验网络邻接矩阵 % mi_threshold 10.5变量顺序按表 3 的节点序列 % 变量索引1事故类型, 2重伤人数, 3死亡人数, 4轻伤人数, ... % 5财产损失, 6事故地点, 7号牌种类, 8性别, 9季节, ... mi_threshold 10.5; mi_values [0, 10.6618, 10.6459, 10.3968, 9.9414, ... 10.7809, 10.6408, 10.6255, 10.5127, 10.3069, ...]; % 邻接矩阵 initialization全部置零 adjacency zeros(14, 14); for i 2:14 % 从第 2 个变量开始检查索引 1 是事故类型 if mi_values(i) mi_threshold % 变量与事故类型之间连有向边影响因素变量 - 事故类型 adjacency(i, 1) 1; end end % 结果变量重伤人数、死亡人数作为事故类型的子节点方向反向 adjacency(1, 2) 1; % 事故类型 - 重伤人数 adjacency(1, 3) 1; % 事故类型 - 死亡人数代码逻辑说明影响因素变量指向“事故类型”符合“因→果”的因果方向“事故类型”指向“重伤人数”和“死亡人数”是因为事故严重程度直接决定伤亡结果。这样构造的先验网络既利用了互信息筛选相关性又通过因果方向的约束避免出现“结果影响原因”的悖论。4. 贝叶斯网络建模从结构学习到参数学习先验网络确定了节点之间的连接骨架但边的方向和是否存在还需要进一步优化。这一步交给基于评分函数的 GTTGreedy Thick Thinning算法完成。GTT 算法分为两个阶段加边阶段和减边阶段。加边阶段从先验网络出发贪心地添加能够提升网络评分的边减边阶段则反向操作删除冗余的边。两阶段交替迭代直到评分不再提升。4.1 GeNIe 3.0 中的模型构建流程在 GeNIe 3.0 中构建该模型建议按以下步骤操作1. 打开 GeNIe 3.0新建网络 2. 手动添加 14 个节点按表 1 的变量名称命名 3. 为每个节点定义状态如“性别”定义“男”“女”两个状态 “事故类型”定义“死亡事故”“受伤事故”“财产损失事故”三个状态 4. 根据先验网络的邻接关系手动连接节点之间的有向边 5. 选择菜单栏 Network - Structure Learning - Greedy Thick Thinning 6. 在参数设置对话框中 - Prior network 选择 Current Network当前网络作为先验 - Score function 选择 BDeu - Equivalent sample size 设置为 10 7. 点击 Learn Structure等待算法迭代收敛 8. 收敛后选择 Parameter Estimation - Expectation Maximization - 迭代次数设置为 100 - 收敛阈值设置为 0.001 9. 点击 Learn Parameters生成条件概率表GTT 算法的关键在于加边和减边两个阶段不是独立的。先加边得到一个偏复杂的网络再减边去除冗余连接这样比单纯从空网络开始搜索更容易跳出局部最优。算法的评分函数选用 BDeu这是贝叶斯网络结构学习中最常用的评分标准之一它同时在拟合度和模型复杂度之间做权衡——BDeu 评分越高说明网络在解释数据的同时保持了一定的简洁性。参数学习使用最大期望算法EM。EM 算法特别适合处理贝叶斯网络中的缺失数据问题——省际客运事故数据虽然经过清洗但仍可能存在一些变量的取值缺失EM 算法通过迭代“期望步骤”和“最大化步骤”来估计模型参数的极大似然值。EM 算法迭代完成后的输出是每个节点的条件概率表。举一个关键的案例“事故类型”节点的条件概率表描述了在给定各影响因素状态下死亡事故、受伤事故和财产损失事故分别发生的概率。论文给出的基准分布为死亡事故 18%、受伤事故 69%、财产损失事故 13%——这个分布与原始数据中的样本比例一致说明参数学习没有引入大的偏差。4.2 模型验证ROC 曲线与 AUC模型建完后必须回答一个关键问题这个网络的预测能力到底怎么样单看训练集上的准确率没有意义因为可能出现“记住训练样本”而非“学到规律”的情况。论文采用 ROC 曲线和 AUC 值来评估模型泛化能力并与对照组进行比较。ROC 曲线的横轴是假阳性率把非死亡事故预测为死亡事故的比例纵轴是真阳性率正确预测为死亡事故的比例。曲线越靠近左上角说明模型在保持低误报率的同时有高检出率。AUC 是 ROC 曲线下方的面积取值在 0.5 到 1 之间AUC0.5 表示模型与随机猜测无异。# Python 代码示例计算 ROC 曲线和 AUC 值 # 假设 y_true 为真实标签y_pred_proba 为模型输出的预测概率 from sklearn.metrics import roc_curve, auc from sklearn.preprocessing import label_binarize # 将三分类标签转换为二分类问题死亡事故 vs 其他 y_binary (y_true 死亡事故).astype(int) y_score y_pred_proba[:, 0] # 取死亡事故类别的预测概率 fpr, tpr, thresholds roc_curve(y_binary, y_score) roc_auc auc(fpr, tpr) print(fAUC {roc_auc:.6f}) # 绘制 ROC 曲线 import matplotlib.pyplot as plt plt.figure(figsize(6, 5)) plt.plot(fpr, tpr, b-, labelfAUC {roc_auc:.6f}) plt.plot([0, 1], [0, 1], r--, labelRandom Guess (AUC 0.5)) plt.xlabel(False Positive Rate) plt.ylabel(True Positive Rate) plt.legend(loclower right) plt.show()这篇模型的 AUC 均值达到 0.644588高于对照组。0.644 这个值不算高但在交通事故严重程度预测领域属于正常水平——因为事故严重程度受到大量随机因素影响即使是好的模型也不可能达到 0.9 以上的 AUC。关键是与对照组的对比论文设置了两个对照组一是相同建模方法下对比等宽离散和 Hierarchical 聚类离散模型二是相同离散方法下对比纯数据模型和专家知识模型。对比结果显示CACC 离散 互信息先验网络的组合在 ROC 曲线上全面优于等宽离散和纯数据模型也优于专家知识模型。这说明两个问题第一CACC 离散确实比等宽离散保留更多有效信息第二用互信息从数据中提取先验知识比依赖专家经验建模在泛化能力上更有优势——这在某种程度上挑战了“专家知识不可替代”的传统观点。除了 ROC 曲线论文还用留一法做了分类精度测试103 条“死亡事故”命中 102 条512 条“受伤事故”命中 497 条125 条“财产损失事故”命中 121 条整体命中率 97.3%。这个命中率看似很高但需要谨慎解读——因为数据集中“受伤事故”占比 69%即使把所有样本都预测为“受伤事故”准确率也能达到 69%。97.3% 的命中率说明模型确实学到了有效规律但真正有区分度的指标是各类别的精确率和召回率尤其是少数类“死亡事故”的召回率。注意AUC 为 0.644 说明模型的判别能力属于中等水平不能期望它准确预测每一起事故的严重程度。在实际应用中这类模型更适合用于风险因素筛查和安全管理优先级排序而不是事故等级预测。5. 敏感度分析与后验概率从模型到管理建议模型建好后真正对行业管理有直接价值的是“哪个因素对事故严重程度影响最大”以及“某个因素处于特定状态时事故严重程度会如何变化”。这两类问题分别对应敏感度分析和后验概率分析。5.1 敏感度分析找出关键风险因素敏感度分析的核心思想是轻微扰动某个变量的取值观察“事故类型”节点概率分布的变化幅度。变化幅度越大说明该变量对事故严重程度的“杠杆作用”越强——在安全管理资源有限的情况下应该优先管理这些高杠杆因素。在 GeNIe 3.0 中执行敏感度分析 1. 选中结果节点“事故类型” 2. 菜单栏选择 Network - Sensitivity Analysis 3. 在目标节点列表中确认“事故类型”已选中 4. 点击 Calculate等待软件计算所有节点对目标节点的敏感度指数 5. 查看输出结果表按敏感度指数降序排列敏感度分析的结果显示天气敏感度均值 0.184、性别0.1486、车辆类型0.1012对事故严重程度的影响最大。这个排序与互信息排序有明显差异——互信息中“事故地点”排第一但敏感度分析中“天气”排第一。原因在于敏感度分析考虑的是“扰动效应”即某个变量状态变化对事故严重程度分布的边际影响而互信息衡量的是整体相关性。一个变量可能在整体上与事故类型高度相关但它的状态分布比较单一比如“事故地点”的“路口”和“路段”分布相对均衡对事故严重程度的边际影响反而不如一些状态变化剧烈的变量。5.2 条件概率分析量化每个因素的实际影响敏感度分析告诉我们“哪些因素重要”条件概率分析则告诉我们“怎么重要”——具体到某个因素的某个类别它使得死亡事故发生的概率比基准值高了多少或低了多少。以“性别”为例基准情况下死亡事故占比 18%但将“性别”设为“女性”作为证据后死亡事故的比例上升。具体的权重计算方法是先分别计算“女性”状态下死亡事故和死亡人数达到最严重类3人的条件概率取平均值并做归一化再乘以敏感度归一化值得到“女性”这个类别对事故严重程度的综合影响权重。以“性别”为例的条件概率分析结果 - 女性死亡事故发生概率相比基准值上升影响权重最高 - 男性死亡事故概率上升幅度小于女性影响权重约为女性的 45% 以“车辆类型”为例 - 中型客车对死亡事故和多人死亡的影响权重最高 - 大型客车影响权重仅次于中型客车 - 小型客车相对安全但更容易引发人员受伤 以“天气”为例 - 雪、大风、雾对事故严重程度的影响权重最高达到 8.8% - 雨天权重中等 - 晴天影响最小论文最值得关注的结论是中型客车对事故严重程度的影响超过大型客车而小型客车相对安全。这与直觉中“车越大越安全”的认知相反。可能的解释是中型客车的驾驶员群体在驾驶习惯、运营里程和行驶环境方面可能处于一个“中间地带”——既没有大型客车那样严格的管理规范也没有小型客车那样的轻便灵活性反而成为风险最高的车型。这个结论直接给安全管理提了个醒不能简单按车辆大小排序优先级应该深入分析不同车型的实际运营特征和事故模式。5.3 后验概率分析的实操方法与解读后验概率分析是条件概率分析的延伸。它的操作方式是将某个影响因素设为“证据”即确定其状态更新整个贝叶斯网络观察结果变量死亡人数、轻伤人数、重伤人数、财产损失的各个状态发生概率如何变化。在 GeNIe 3.0 中执行后验概率分析 1. 点击结果节点“死亡人数”右键选择 Set Evidence 2. 在证据设置对话框中将某个影响因素节点设为特定状态 例如将“性别”设为“女性” 3. 点击 Update Beliefs 更新网络信念 4. 查看“死亡人数”节点的概率分布变化 5. 重复以上步骤依次对不同影响因素的各个状态进行分析以“性别女性”为证据时“死亡人数”节点的概率分布会发生明显变化死亡人数为 0 的概率下降 2%死亡人数为 1 的概率上升 2%死亡人数为 2 的概率上升 8%死亡人数为 3 的概率上升 8%死亡人数大于 3 的概率上升 12%。也就是说女性驾驶员一旦发生事故更倾向于造成多人死亡。论文给出的解释是女性驾驶员在紧急情况下的应急处置能力、身体承受力等因素与男性存在差异但这个结论需要谨慎解读——它也可能与女性驾驶员的驾驶里程、驾驶车型分布等混淆因素有关。同样值得关注的结论包括“年龄”与死亡人数成正比但“27 岁以下”驾驶员更容易引发受伤事故。年轻驾驶员反应快但经验不足发生事故时车辆速度可能更快导致受伤概率高但致命概率低。“路段”比“路口”更容易导致死亡事故。交叉口有交通信号灯和减速带等管控措施事故以轻微碰撞为主路段上行驶速度更快事故碰撞能量更大致死率更高。凌晨 00:00—05:00 时段死亡风险显著上升群伤事故概率平均上升 9%。夜间驾驶视野差、疲劳驾驶率高、车速快这些都放大了事故后果。恶劣天气雪、大风、雾与死亡人数、受伤人数正相关且更容易引发群伤事故。但模型认为天气与财产损失无直接关联——恶劣天气下驾驶员会降低速度反而减少了重大财产损失的可能性。这些结论可以从 5 张条件概率表中提取。投产使用时可以用下面的 Python 代码做批量分析# 批量计算不同证据条件下的后验概率变化 # 这里使用 pgmpy 库作为示例 from pgmpy.models import BayesianNetwork from pgmpy.estimators import MaximumLikelihoodEstimator from pgmpy.inference import VariableElimination # 定义网络结构根据模型学习结果 model BayesianNetwork([ (事故地点, 事故类型), (性别, 事故类型), (季节, 事故类型), (车辆类型, 事故类型), (事故类型, 死亡人数), (事故类型, 重伤人数), ]) # 加载数据并用 MLE 估计参数 model.fit(data, estimatorMaximumLikelihoodEstimator) # 创建推理引擎 infer VariableElimination(model) # 基准概率无证据时 baseline infer.query(variables[死亡人数]) baseline_probs baseline.values # 设置证据性别 女性假设 1 表示女性 evidence {性别: 1} posterior infer.query(variables[死亡人数], evidenceevidence) # 计算概率变化 print(死亡人数概率变化) for i, (b, p) in enumerate(zip(baseline_probs, posterior.values)): print(f死亡人数{i}: 基准 {b:.4f} - 后验 {p:.4f}, 变化 {p-b:.4f})这段代码展示了如何在 Python 中用 pgmpy 复现论文的后验概率分析流程。实际使用时需要根据 GeNIe 3.0 中学习到的网络结构和条件概率表替换对应的变量名和数值。注意这里的网络结构是简化的演示版本完整模型包含 14 个节点和更多边。5.4 核心结论到管理措施将敏感度分析、条件概率分析和后验概率分析的结论汇总可以锁定几个最值得优先干预的风险面高风险因素清单按影响权重排序 1. 女性驾驶员死亡事故和群伤事故风险显著偏高 2. 中型客车整体事故严重程度影响权重最高 3. 雪、大风、雾天气事故严重程度和群伤风险同步上升 4. 路段非路口死亡事故风险高于路口 5. 秋冬季节死亡和受伤风险均高于春夏 6. 凌晨 00:00—05:00群伤事故风险最高 7. 左转弯、停车、倒车、掉头等驾驶行为更易导致死亡 8. 变更车道、躲避障碍、驶离路面重大财产损失风险高这些结论对应的管理动作可以是对女性驾驶员增加应急处置专项培训对中型客车的安全检查频次和设备标准进行针对性提升在恶劣天气预警时启动省际客运降速或停运机制对凌晨时段的驾驶排班做强制休息约束在路段事故多发点增设警示标志和测速设备。提示贝叶斯网络输出的相关性结论不能直接等同于因果结论。“女性驾驶员更容易导致死亡事故”这类分析结果是统计数据规律背后可能隐藏着驾驶里程、车型偏好、线路特征等混淆变量。在制定管理措施前建议结合业务背景和更细粒度的数据做交叉验证。6. 用 ROC 曲线快速验证网络结构的调整效果模型投入使用后网络结构不是一成不变的。随着省际客运事故数据的持续积累原来用 741 条样本学到的条件概率表需要更新甚至某些变量之间的依赖关系可能发生改变。这就涉及一个实际问题调整网络结构后如何快速判断调整是变好还是变差只用整体分类准确率验证一个陷阱准确率对类别不平衡极不敏感。前面提到“受伤事故”占 69%即使网络完全不学习“死亡事故”的规律只要把所有样本都判为“受伤事故”准确率也有 69%。ROC 曲线和 AUC 值能更灵敏地反映模型对少数类的判别能力尤其是“死亡事故”这类高风险低概率事件。在 GeNIe 3.0 中做结构调整后的验证常用做法是导出一组模型预测概率再在 Python 中计算 ROC 和 AUC# 调整网络结构后验证效果 # 从 GeNIe 中导出模型预测概率 # 对测试集中的每条样本记录真实标签和模型输出的各类别预测概率 # 保存为 CSV 文件真实标签、死亡事故概率、受伤事故概率、财产损失概率 import pandas as pd from sklearn.metrics import roc_auc_score # 读取 GeNIe 导出的预测结果 results pd.read_csv(model_predictions.csv) # 计算宏观平均 AUCone-vs-rest 方式 auc_death roc_auc_score( (results[真实标签] 死亡事故).astype(int), results[死亡事故概率] ) auc_injury roc_auc_score( (results[真实标签] 受伤事故).astype(int), results[受伤事故概率] ) auc_property roc_auc_score( (results[真实标签] 财产损失事故).astype(int), results[财产损失概率] ) macro_auc (auc_death auc_injury auc_property) / 3 print(f死亡事故 AUC {auc_death:.4f}) print(f受伤事故 AUC {auc_injury:.4f}) print(f财产损失事故 AUC {auc_property:.4f}) print(f宏观平均 AUC {macro_auc:.4f})实际验证时需要重点盯住两个指标整体宏观 AUC 是否下降超过 0.01以及“死亡事故”类别的 AUC 是否下降超过 0.02。如果整体 AUC 略有上升但“死亡事故”AUC 明显下降说明结构调整提升了多数类表现但牺牲了少数类——这对交通安全管理是不能接受的。在评估网络结构调整时可以引入 ROC 曲线下面积做模型比选的决策支持批次结构微调对比的验证方法 1. 保留原始模型 M1备份其条件概率表和 AUC 结果 2. 在 GeNIe 中调整网络结构如增加或删除一条有向边学习新参数得到模型 M2 3. 在同一测试集上分别计算 M1 和 M2 的 ROC 曲线及 AUC 4. 对比两模型的 AUC 差异 - 若 M2 的宏观 AUC 提升超过 0.005且“死亡事故”AUC 不下降保留调整 - 若 M2 的宏观 AUC 提升但“死亡事故”AUC 下降谨慎采纳 - 若宏观 AUC 下降但“死亡事故”AUC 上升可以针对性优化死亡事故预测 5. 对每个候选结构调整重复以上流程留下有效的调整项回滚无效的调整项用同一套验证流程依次检验每个候选调整最终保留能同时提升少数类 AUC 和整体宏观 AUC 的结构修改。反复用 ROC 做小步验证先拿历史数据验证不影响监控指标再替换线上模型做灰度对比比一次性推翻重学的思路更稳。后续可考虑两类改进方向一是把原始事故记录中的 GPS 轨迹、违规记录、车辆检测数据等字段补充成新的变量节点二是尝试用多折交叉验证替代留一法来减少单次划分带来的评估波动——但样本量只有 741 条时多折交叉验证的稳定性提升有限优先建议补充变量来源等数据量突破 2000 条后再引入动态结构学习重新建模。本文还有配套的精品资源点击获取