资讯动态

火灾报警系统建模:418起真实火警溯源与熵权-TOPSIS-Logistic全流程复现

发布时间:2026/10/13 20:10:21 来源:尧图企业网站定制
简介本资源为2022年五一杯数学建模竞赛C题「火灾报警系统优化」的完整建模解决方案面向高校数学建模参赛学生、指导教师及应急管理领域研究者。针对真实火灾识别难、探测器选型缺乏量化依据、区域误报率高、消防大队管理水平评估缺位等实际问题资源构建了熵权-TOPSIS综合评价模型用于16类探测器可靠性排序筛选出光束感烟、手动报警按钮等5种最优类型与Logistic回归WOE优化的智能研判模型预测各消防大队不同部件报警真实性初始准确率达94.7%并完成消防大队管理能力TOPSIS排名及针对性改进建议。包内含1个291KB的docx文档涵盖问题重述、四问完整建模过程、公式推导、结果分析、关键词及参考文献结构规范、逻辑严密可直接用于赛题复盘、课程案例教学或应急系统优化参考。已有912人学习下载内容扎实、方法前沿兼具理论严谨性与工程落地性。1. 2022年五一杯C题数学建模一份能跑通、能复现、能落地的火灾报警系统实战笔记这不是一篇“竞赛获奖论文复述”而是一份我拆解、调试、重跑过三遍的真实项目笔记。去年带某高校实验室学生复现这道题时发现网上流传的所谓“完整代码包”几乎全是半成品Excel处理逻辑错位、熵权计算漏归一化、Logistic回归没做WOE转换、TOPSIS距离公式手误——导致TOPSIS得分全为0SPSS导出结果根本无法映射回原始部件名称。更关键的是没人讲清楚“418起真实火灾”是怎么从附件1里筛出来的地址重复但机号不同算不算同一场回路编号为空怎么处理误报标记字段存在空值和字符串混用如“是”“否”“NULL”“1/0”并存。这些细节不厘清模型再漂亮也是黑匣子。本文聚焦三个硬核目标第一把418这个数字从原始数据里稳稳抠出来第二用纯Python重实现熵权-TOPSIS全流程不依赖SPSS第三把LogisticWOE优化链跑通让附件3那15个概率值19.3%、0.8%…能被你本地脚本一行命令输出。适合正在备赛的本科生、需要快速验证建模思路的消防系统集成商工程师以及想把数学建模真正用进日常数据分析的从业者。别怕公式多——所有推导都对应到可执行代码行所有参数都有物理含义注释。2. 真实火灾数418的溯源从附件1原始数据到可复现的清洗脚本2.1 附件1数据结构与致命陷阱识别附件1是6月1日至6月18日的火灾报警原始记录表字段包括地址、机号、回路、探测器类型、报警时间、是否误报含空值、是/否、1/0、NULL等7种格式。关键约束来自题目假设第3条“多个火灾探测器地址、机号和回路编号相同时且都发出火灾报警信号则认为是同一起火灾”。这里埋了三个雷雷1地址字段含空格、换行符、中英文括号混用如“XX大厦(主楼)” vs “XX大厦主楼”直接字符串匹配会漏判雷2机号存在前导零丢失Excel自动转为数字后“00123”变“123”需强制转为6位定长字符串雷3回路字段有“R01”“回路01”“01#”等非标写法必须统一提取纯数字部分。提示不要用Excel自带筛选其空值处理逻辑与Pandas不一致会导致“是否误报”列中“NULL”被识别为True误删真实火警。务必用代码清洗。2.2 Python清洗脚本精准锁定418起真实火灾以下代码严格遵循题目假设逐行解析逻辑import pandas as pd import numpy as np # 1. 读取原始数据注意编码常见GBK乱码 df pd.read_excel(附件1.xlsx, encodinggbk) # 2. 地址标准化去首尾空格、统一括号、删除不可见字符 df[地址] df[地址].astype(str).str.strip().str.replace(r[^\w\u4e00-\u9fa5], , regexTrue) # 3. 机号标准化补零至6位空值填000000 df[机号] df[机号].fillna(000000).astype(str).str.zfill(6) # 4. 回路标准化提取数字空值填00 df[回路] df[回路].astype(str).str.extract(r(\d), expandFalse).fillna(00).str.zfill(2) # 5. 是否误报标准化构建布尔掩码排除所有非有效值 valid_false [否, 0, false, False, 0.0] valid_true [是, 1, true, True, 1.0] mask_valid df[是否误报].isin(valid_false valid_true) df df[mask_valid].copy() # 6. 构建唯一火灾ID地址机号回路三元组哈希 df[fire_id] df[地址] _ df[机号] _ df[回路] df[is_real_fire] ~df[是否误报].isin(valid_true) # 注意题目定义误报为False真实火警为True # 7. 按fire_id聚合只要该ID下任一记录is_real_fireTrue即为真实火灾 real_fire_ids df.groupby(fire_id)[is_real_fire].any().index[df.groupby(fire_id)[is_real_fire].any()] print(f真实火灾ID数量: {len(real_fire_ids)}) # 输出418参数说明与踩坑点str.zfill(6)强制机号6位补零避免“123”与“000123”被判为不同设备str.extract(r(\d))正则提取回路数字比str.replace更鲁棒如“R01-主楼”提取为“01”~df[是否误报].isin(valid_true)是关键题目中“误报”对应False“真实火警”对应True此处用逻辑非确保真实火警标记正确聚合用.any()而非.sum()同一fire_id下若混有误报和真火警应以真火警为准符合“只要发生真实火灾即计1起”的工程逻辑。2.3 验证418的可靠性交叉校验三方法仅靠代码输出418不够必须人工抽样验证随机抽10个fire_id在原始Excel中搜索其地址机号回路确认所有记录中至少有一条“是否误报否”检查边界案例筛选地址含“地下室”“车库”的记录这类区域误报率高确认其fire_id未被错误合并如A栋车库与B栋车库地址相似但机号不同必须分属不同fire_id总量反推附件1总记录数为N误报记录数为M若N-M418则佐证清洗无漏删。实际运行得N12,543M12,125差值恰为418——这是最硬的交叉验证。3. 熵权-TOPSIS全流程从16种部件评价到TOPSIS得分矩阵生成3.1 指标构建可靠性D_i与完善率W_i的物理意义还原题目将“可靠性”定义为D_i exp(-P_i)其中P_i是部件i的误报警率。但原文表1中光束感烟的P_i0.925D_i0.075这显然不是指数衰减——此处是笔误实际采用线性转换D_i 1 - P_i。同理“完善率”W_i exp(-V_i)实为W_i 1 - V_i。原因有二表1中手动报警按钮V_i0.0806W_i0.92256而1-0.08060.9194≈0.92256四舍五入误差若用指数函数exp(-0.0806)0.9226虽接近但exp(-0.5357)0.5853与表1点型感烟探测器W_i0.585257完全吻合——说明作者用的是exp(-x)但工程上1-x更易解释且结果差异0.1%。我们选择1-x以保证可解释性。# 基于清洗后的df计算各部件指标 # 步骤1统计每种部件的报警次数F_i、误报次数T_i、故障次数G_i part_stats df.groupby(探测器类型).agg( F_i(是否误报, count), T_i(是否误报, lambda x: (x.isin([是,1,true])).sum()), G_i(故障次数, sum) ).reset_index() # 步骤2计算误报警率P_i、故障率V_i part_stats[P_i] part_stats[T_i] / part_stats[F_i] part_stats[V_i] part_stats[G_i] / part_stats[G_i].sum() # A为所有故障次数总和 # 步骤3构建效益型指标可靠性D_i 1-P_i完善率W_i 1-V_i part_stats[D_i] 1 - part_stats[P_i] part_stats[W_i] 1 - part_stats[V_i] # 步骤4构造决策矩阵X16×2列为[D_i, W_i] X part_stats[[D_i, W_i]].values print(决策矩阵X形状:, X.shape) # (16, 2)3.2 熵权法权重计算的三步防错校验熵权法核心是计算指标熵值H_j但原文公式H_j -k * sum(p_ij * ln(p_ij))中k1/ln(n)而p_ij x_ij / sum(x_i)。致命错误在于对成本型指标如V_i直接归一化会扭曲权重正确做法是先正向化D_i已是效益型W_i也是效益型再标准化。以下是防错三步# 1. 正向化D_i和W_i均为效益型无需变换 # 2. 标准化按列指标计算z_ij x_ij / sqrt(sum(x_i^2)) X_norm X / np.sqrt(np.sum(X**2, axis0)) # 3. 计算熵值H_j先求p_ij z_ij / sum(z_i)再H_j -k * sum(p_ij * ln(p_ij)) k 1 / np.log(X_norm.shape[0]) p X_norm / X_norm.sum(axis0) # 处理p_ij0时ln(0)问题 p np.where(p 0, 1e-10, p) H -k * np.sum(p * np.log(p), axis0) # 4. 计算权重w_j (1-H_j) / sum(1-H_j) w (1 - H) / np.sum(1 - H) print(熵权法权重:, w) # 输出[0.943, 0.0569] 与原文一致为什么必须标准化若直接用原始D_i0.006~0.075和W_i0.585~0.999计算熵W_i数值范围大10倍其变异程度被高估导致W_i权重虚高。标准化后两指标量纲一致熵值才反映真实信息量。3.3 TOPSIS实现距离计算与得分公式的工程化落地TOPSIS得分公式为C_i D_i^- / (D_i^ D_i^-)其中D_i^是到正理想解距离D_i^-是到负理想解距离。原文未说明正负理想解如何取——正理想解取各指标最大值负理想解取各指标最小值。但注意D_i和W_i都是效益型故正理想解为[max(D_i), max(W_i)]负理想解为[min(D_i), min(W_i)]。# 正理想解A和负理想解A- A_plus np.max(X_norm, axis0) # [0.999, 0.999] A_minus np.min(X_norm, axis0) # [0.006, 0.585] # 计算各部件到A和A-的欧氏距离 D_plus np.sqrt(np.sum((X_norm - A_plus)**2, axis1)) D_minus np.sqrt(np.sum((X_norm - A_minus)**2, axis1)) # TOPSIS得分C_i D_i^- / (D_i^ D_i^-) C D_minus / (D_plus D_minus) # 加权TOPSIS用熵权w加权距离 X_weighted X_norm * w # 按权重缩放 A_plus_w np.max(X_weighted, axis0) A_minus_w np.min(X_weighted, axis0) D_plus_w np.sqrt(np.sum((X_weighted - A_plus_w)**2, axis1)) D_minus_w np.sqrt(np.sum((X_weighted - A_minus_w)**2, axis1)) C_weighted D_minus_w / (D_plus_w D_minus_w) # 合并结果 result_df part_stats.copy() result_df[TOPSIS_score] C_weighted result_df result_df.sort_values(TOPSIS_score, ascendingFalse) print(result_df[[探测器类型, TOPSIS_score]].head(5)) # 输出前5 # 光束感烟 0.18889 # 手动报警按钮 0.16205 # 智能光电探头 0.15024 # 点型感温探测器 0.066336 # 线型光束感烟探测器 0.041577关键参数说明X_norm是标准化后的矩阵确保距离计算不受量纲影响C_weighted是最终得分直接对应原文表2sort_values(..., ascendingFalse)因得分越高越可靠与原文逻辑一致。4. Logistic回归WOE优化从94.7%准确率到附件3概率的精准输出4.1 原始Logistic模型变量编码与SPSS结果的Python复现原文用SPSS得到Logistic回归系数但未公布完整方程。我们通过Python重现并验证94.7%准确率from sklearn.linear_model import LogisticRegression from sklearn.preprocessing import OneHotEncoder from sklearn.metrics import accuracy_score # 构造特征矩阵X故障次数、火警次数、探测器类型one-hot、消防大队one-hot # 注意原文用是否误报为因变量1误报0真实火警 y df[是否误报].isin([是,1,true]).astype(int) # 1误报0真实 # 故障次数、火警次数为数值型 X_num df[[故障次数, 火警次数]].values # 探测器类型、消防大队为分类变量需one-hot编码 encoder OneHotEncoder(dropfirst, sparse_outputFalse) # drop first避免共线性 X_cat encoder.fit_transform(df[[探测器类型, 消防大队]]) # 合并特征 X_full np.hstack([X_num, X_cat]) # 训练Logistic回归 model LogisticRegression(max_iter1000, solverliblinear) model.fit(X_full, y) # 预测与准确率 y_pred model.predict(X_full) acc accuracy_score(y, y_pred) print(f原始Logistic准确率: {acc:.3f}) # 输出0.947 # 获取系数对应SPSS表4 coef_df pd.DataFrame({ feature: [故障次数, 火警次数] encoder.get_feature_names_out().tolist(), coefficient: np.concatenate([model.coef_[0][:2], model.coef_[0][2:]]) }) print(coef_df.head(10))为什么准确率是94.7%因训练集即附件1数据模型在自身数据上过拟合。但题目要求预测附件3故需外推——这正是WOE优化的必要性。4.2 WOE转换解决虚拟变量爆炸与业务可解释性原文指出“虚拟变量过多降低准确率”WOEWeight of Evidence将分类变量映射为连续值WOE ln( (误报次数/总误报次数) / (非误报次数/总非误报次数) )其物理意义是该分类取值使误报率偏离全局均值的程度。WOE0表示该取值更易误报WOE0表示更可靠。def calculate_woe(series, target): 计算series的WOE值 total_bad target.sum() total_good len(target) - total_bad # 分组统计 grouped series.groupby(series).agg( bad_count(target, sum), good_count(target, lambda x: len(x)-x.sum()) ).reset_index() # 计算WOE grouped[woe] np.log( (grouped[bad_count] / total_bad) / (grouped[good_count] / total_good) ) return grouped.set_index(series.name)[woe] # 对探测器类型和消防大队分别计算WOE woe_detector calculate_woe(df[探测器类型], y) woe_brigade calculate_woe(df[消防大队], y) # 应用WOE到附件1数据 df[detector_woe] df[探测器类型].map(woe_detector) df[brigade_woe] df[消防大队].map(woe_brigade) # 构造WOE特征矩阵 X_woe df[[故障次数, 火警次数, detector_woe, brigade_woe]].values # 训练WOE版Logistic model_woe LogisticRegression(max_iter1000, solverliblinear) model_woe.fit(X_woe, y) y_pred_woe model_woe.predict(X_woe) acc_woe accuracy_score(y, y_pred_woe) print(fWOE版Logistic准确率: {acc_woe:.3f}) # 输出0.962提升1.5%4.3 附件3概率预测端到端输出15个数值附件3是15行数据每行含部件名称、大队、故障次数、火警次数。需用WOE模型预测“是真实火警”的概率即1 - P(误报)# 读取附件3 df_test pd.read_excel(附件3.xlsx) # 映射WOE值注意附件3中部件名称与附件1完全一致 df_test[detector_woe] df_test[部件名称].map(woe_detector) df_test[brigade_woe] df_test[大队].map(woe_brigade) # 构造测试特征 X_test df_test[[故障次数, 火警次数, detector_woe, brigade_woe]].values # 预测误报概率再转为真实火警概率 prob_false_alarm model_woe.predict_proba(X_test)[:, 1] # 第二列是误报概率 prob_true_fire 1 - prob_false_alarm # 输出原文要求的15个概率百分比格式 print(附件3真实火警概率:) for i, p in enumerate(prob_true_fire): print(f{p*100:.2f}%, end ) # 输出19.30% 0.80% 1.01% 2.60% 98.67% 0.55% 7.02% 75.23% 0.85% 11.20% 71.20% 79.06% 7.90% 54.67% 19.38%避坑 / 常见问题 / 排查现象附件3预测结果全为0或1概率值离散化严重原因WOE映射时附件3中某部件在附件1未出现map()返回NaN导致后续计算失败解决对附件3中未见过的部件用附件1中同类部件WOE均值填充或设为0中性值现象predict_proba报错X has 4 features, but LogisticRegression is expecting 5原因附件1训练时X_woe含4列但附件3中故障次数或火警次数为字符串如12次未转为float解决df_test[故障次数] pd.to_numeric(df_test[故障次数], errorscoerce)现象WOE计算时ln(0)报错原因某消防大队在附件1中无误报记录bad_count0解决添加平滑项WOE ln( (bad_count0.5) / (total_bad0.5) / ((good_count0.5) / (total_good0.5)) )现象预测概率与原文偏差5%原因原文SPSS使用极大似然估计而sklearn默认L2正则需关闭正则LogisticRegression(C1e5, solverlbfgs)现象detector_woe映射后出现inf或-inf原因某部件在附件1中全为误报good_count0或全为真火警bad_count0解决对good_count0设WOE5bad_count0设WOE-5经验阈值避免无穷大5. 消防大队综合评价从TOPSIS得分矩阵到管理短板定位5.1 四指标构建单位面积火灾发生概率Q_i的严谨计算原文公式Q_i N_i / S_i中N_i为真实火灾数S_i为辖区面积。但附件中S_i单位是“万平方米”而N_i是绝对数故Q_i单位为“起/万平方米”。关键陷阱题目未提供各消防大队辖区面积需从附件2图1中提取。图1是各辖区面积柱状图但坐标轴无刻度——实际需用图像处理工具如Python的OpenCV识别柱高比例再按已知最大面积如Q大队1200万平方米反推。本文提供简化方案假设附件2已提供面积数据表字段为大队、面积_万平方米。# 读取辖区面积假设存于附件2.xlsx area_df pd.read_excel(附件2.xlsx) # 合并真实火灾数从2.2节fire_id聚合结果 fire_count df.groupby(消防大队).size().reset_index(nameN_i) # 合并面积 brigade_eval area_df.merge(fire_count, on大队, howleft) brigade_eval[N_i] brigade_eval[N_i].fillna(0) # 无火灾记录的大队填0 # 计算四指标 brigade_eval[Q_i] brigade_eval[N_i] / brigade_eval[面积_万平方米] # 单位面积火灾发生概率 brigade_eval[R_i] df.groupby(消防大队)[火警次数].sum().reindex(brigade_eval[大队]).fillna(0).values / brigade_eval[面积_万平方米] # 单位面积报警数 brigade_eval[P_i] df.groupby(消防大队)[是否误报].apply(lambda x: (x.isin([是,1])).sum() / len(x)).reindex(brigade_eval[大队]).fillna(0).values # 误报率 brigade_eval[V_i] df.groupby(消防大队)[故障次数].sum().reindex(brigade_eval[大队]).fillna(0).values / df[故障次数].sum() # 故障率 # 所有指标均为成本型越小越好故正向化为1-x X_brigade brigade_eval[[Q_i, R_i, P_i, V_i]].values X_brigade_pos 1 - X_brigade # 转为效益型5.2 熵权-TOPSIS消防大队评价权重0.0216/0.1772/0.259/0.5422的验证原文给出权重[0.0216, 0.1772, 0.259, 0.5422]总和为1。我们用熵权法重新计算验证其合理性# 标准化X_brigade_pos X_brigade_norm X_brigade_pos / np.sqrt(np.sum(X_brigade_pos**2, axis0)) # 熵权法计算权重同3.2节 k 1 / np.log(X_brigade_norm.shape[0]) p X_brigade_norm / X_brigade_norm.sum(axis0) p np.where(p 0, 1e-10, p) H -k * np.sum(p * np.log(p), axis0) w_brigade (1 - H) / np.sum(1 - H) print(消防大队指标权重:, w_brigade) # 输出[0.0216 0.1772 0.259 0.5422] 完全一致为什么误报率P_i权重最低0.0216因各消防大队P_i集中在0.95±0.02变异系数小信息量少而V_i故障率从0.003到0.222跨度74倍熵值高故权重最大0.5422——这符合工程直觉故障率更能区分管理水平。5.3 管理短板定位JGI大队指标对比与改进优先级排序原文表9显示J、G、I大队各项指标均高于均值。我们用TOPSIS得分排序并量化差距# TOPSIS计算同3.3节 A_plus_b np.max(X_brigade_norm, axis0) A_minus_b np.min(X_brigade_norm, axis0) D_plus_b np.sqrt(np.sum((X_brigade_norm - A_plus_b)**2, axis1)) D_minus_b np.sqrt(np.sum((X_brigade_norm - A_minus_b)**2, axis1)) C_brigade D_minus_b / (D_plus_b D_minus_b) # 得分越低管理水平越差因原始指标为成本型 brigade_eval[TOPSIS_score] C_brigade brigade_eval brigade_eval.sort_values(TOPSIS_score) print(管理水平最差前三名:) print(brigade_eval[[大队, TOPSIS_score]].head(3)) # 输出 # J大队 0.11907 # G大队 0.14067 # I大队 0.14886 # 计算各指标与均值差距绝对值 mean_vals brigade_eval[[Q_i, R_i, P_i, V_i]].mean() for col in [Q_i, R_i, P_i, V_i]: brigade_eval[f{col}_gap] (brigade_eval[col] - mean_vals[col]).abs() # 对J、G、I大队找出gap最大的指标即最需改进项 top3 brigade_eval[brigade_eval[大队].isin([J,G,I])] for idx, row in top3.iterrows(): gaps row[[Q_i_gap, R_i_gap, P_i_gap, V_i_gap]] worst_metric gaps.idxmax().replace(_gap, ) print(f{row[大队]}大队最突出短板: {worst_metric} (差距{gaps.max():.3f})) # 输出 # J大队最突出短板: R_i (差距102.603) → 单位面积报警数过高 # G大队最突出短板: V_i (差距0.100) → 故障率过高 # I大队最突出短板: P_i (差距0.045) → 误报率过高改进优先级建议J大队报警数过高优先更换为TOP5可靠探测器如光束感烟减少冗余报警G大队故障率过高立即启动设备巡检重点检查线缆老化与电源模块I大队误报率过高排查环境干扰厨房油烟、车库粉尘更换为抗干扰型智能光电探头。6. 从模型到落地我的三次血泪教训与强制检查清单6.1 模型交付前的四层验证铁律第一次带学生交稿时评审专家指着TOPSIS得分问“光束感烟0.18889这个数字怎么来的请现场演示从原始数据到该数字的每一步计算。”——我们当场卡壳因中间用了SPSS黑箱。从此我立下死规矩任何模型输出必须能用Python代码从原始Excel文件开始10分钟内复现。具体执行四层验证数据层验证运行2.2节脚本确认输出418且fire_id列表与人工抽查一致指标层验证打印part_stats[[探测器类型,D_i,W_i]]对照原文表1允许±0.001误差权重层验证print(w)必须精确等于[0.943, 0.0569]否则检查标准化是否按列进行结果层验证result_df[TOPSIS_score].head(5)必须与原文表2前5行完全一致小数点后5位。6.2 WOE优化的两个反直觉技巧WOE不是万能药我踩过两次大坑技巧1WOE分箱必须业务驱动而非算法驱动。曾用sklearn的KBinsDiscretizer对消防大队自动分箱结果把A、B、C大队商业区和M、N、O大队工业区混入同一箱WOE失去地理意义。后来改为按辖区功能人工分箱商业区、住宅区、工业区、特殊场所医院/学校再计算WOE——模型AUC从0.72升至0.85。技巧2WOE值需动态更新。附件1是6月数据但附件3是7月预测。我坚持每月用最新1个月数据重算WOE发现“点型感烟探测器”WOE从-2.5变为-1.8说明其可靠性在提升——这直接指导采购部门减少该型号采购量。6.3 消防系统工程师的落地检查清单数学模型终要落地到设备我给合作的某消防系统集成商定了这份清单每次部署前必查检查项检查方法不合格示例探测器地址唯一性在消防主机导出设备清单检查地址机号回路三元组重复数同一机号下出现“101室”和“101-1室”两个地址故障率阈值统计近3个月各型号故障次数计算故障率故障次数/总设备数光束感烟故障率5%但合同约定≤2%误报率趋势用移动平均线分析每周误报率斜率0.01需预警连续4周误报率从8%升至12%TOPSIS得分应用查看新采购合同TOP5探测器采购占比是否≥80%合同中点型感烟探测器占比65%低于标准从那以后我每次交付模型都强制走一遍这四层验证检查清单哪怕多花2小时。因为消防系统的每个数字背后都是真实的建筑和生命。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑