2024 MCM/ICM E题财产保险可持续性Python源码拆解:模糊综合评价、灰色预测与SVM实战
简介这份资源是2024年美国大学生数学建模竞赛ICM Problem E的完整参赛作品围绕财产保险可持续性这一议题用Python构建了从数据预处理到建模预测的全流程方案。内容适合数学建模初学者、进阶学习者以及需要完成课程设计、大作业或毕设立项的同学参考。压缩包共43个文件约18.43MB包含7个Python脚本、16张png与7张svg图表、3份xlsx数据表、2份pdf文档及tex论文源文件等覆盖模糊综合评价、灰色预测、层次分析、支持向量机等多种建模方法。资源中既有模型代码与数据集也有ROC曲线、PCA降维对比、灵敏度分析等可视化结果还附有论文排版文件与说明文档便于读者理解建模思路、复现实验流程并借鉴论文写作结构。目前已有111人学习下载可作为美赛备赛与保险精算建模的实战参考。1. 从一份 2024 MCM/ICM E 题源码包说起财产保险可持续性到底怎么用 Python 落地财产保险的可持续性听起来像宏观政策话题但落到 2024 年美国大学生数学建模竞赛 E 题里它其实是一道非常具体的工程题给定极端天气事件频发、再保险成本上升、承保亏损扩大的背景如何用数据判断一个地区的保险市场是否可持续并给出定价与承保策略。这份Fuck_2024_MCM-ICM-main.zip就是一套完整的解题源码包里面既有 LaTeX 论文、PDF 原题也有从模糊综合评价到灰色预测、再到支持向量机的三套模型代码还有灵敏度分析、ROC 曲线、PCA 降维图等一整套图表产物。如果你正在找一份能直接跑通、能拆开看每个模型怎么衔接的数学建模实战素材或者想拿它当课程设计、大作业、工程实训的底稿这份资源的价值不在于拿了奖而在于它把从数据到结论的链路完整摊开了——你可以看到每个模型输入什么、输出什么、参数怎么调、图怎么画。下面我按自己拆包复现的顺序把这份资源讲透。2. 拆包先看结构三套模型如何对应 E 题的三问2.1 文件清单与模型分工解压后目录分成四块根目录放2024_ICM_Problem_E.pdf原题和README.mdcode目录是全部 Python 脚本data目录是三个 Excel 数据集figure目录是论文里用到的所有图。先别急着跑代码把code里的文件名读一遍基本就能反推出作者的建模思路文件名对应模型作用模型一 模糊综合评价.py模型一对地区保险可持续性做综合评分模型一 隶属函数.py模型一构造模糊评价的隶属度函数模型一.cs模型一可能是 C# 辅助或早期版本可忽略模型二 灰色预测.py模型二预测未来保费/赔付趋势模型二 灰色关联分析.py模型二筛选影响可持续性的关键因子模型二 层次分析.py模型二确定各因子权重模型三 支持向量机.py模型三分类判断地区风险等级svm_model.pkl模型三训练好的 SVM 模型持久化文件draw_Figure_1.py绘图生成论文 Figure_1这套分工是典型的评价—预测—分类三段式模型一回答现在哪个地区不可持续模型二回答未来会怎样模型三回答新地区该归到哪一类。三套模型共享dataset.csv和支持向量机数据集.xlsx所以数据口径是一致的这一点比很多拼凑的源码包强。2.2 环境准备与依赖安装代码是纯 Python 写的没有用到深度学习框架依赖很轻。我一般会先建一个干净虚拟环境避免和系统里的包打架# 创建虚拟环境Python 3.8 及以上都行 python -m venv mcm_env # Windows 激活 mcm_env\Scripts\activate # macOS / Linux 激活 source mcm_env/bin/activate # 安装核心依赖 pip install numpy pandas scikit-learn matplotlib openpyxl scipy这里几个包的分工要说清楚pandas读 Excel 和 CSVscikit-learn提供 SVM、PCA、ROC 计算matplotlib出图openpyxl是 pandas 读写.xlsx的底层引擎缺了它读 Excel 会直接报错。scipy在灰色预测和层次分析里会用到插值和矩阵运算。装完之后建议先跑一句python -c import sklearn; print(sklearn.__version__)确认版本SVM 的predict_proba在不同版本里行为略有差异后面调 ROC 时会踩到。2.3 数据文件先做一次体检data目录下三个 Excel 各有用途支持向量机数据集.xlsx是模型三的训练集模型二预测数据.xlsx是灰色预测的输入序列灵敏度分析.xlsx是最后做参数扰动的底表。跑任何模型前我习惯先看一眼行列数和缺失值import pandas as pd # 逐个读取并体检 for f in [支持向量机数据集.xlsx, 模型二预测数据.xlsx, 灵敏度分析.xlsx]: df pd.read_excel(fdata/{f}) print(f, df.shape) print(df.isnull().sum().sum(), 个缺失值) print(df.head(3))逻辑说明shape告诉你样本量和特征数缺失值数量决定你要不要先做填充head(3)看列名和数据类型。参数上没什么可调的但要注意如果某列被 Excel 存成了文本格式pandas 读进来会是object类型后面送进 SVM 会报could not convert string to float这时候用pd.to_numeric(df[col], errorscoerce)强制转一下。这一步花两分钟能省掉后面半小时的报错排查。3. 模型一模糊综合评价隶属函数怎么写才不翻车3.1 模糊综合评价的原理与选型理由财产保险可持续性不是一个非黑即白的概念一个地区可能赔付率偏高但保费增长也快用传统二值判断会丢掉信息。模糊综合评价的核心是把每个指标映射到 0 到 1 的隶属度再用权重合成一个综合得分。选它而不是简单加权求和是因为它能处理指标边界模糊的问题——比如保费增长率 5% 到底算好还是差用隶属函数可以给出 0.6 这种中间值而不是硬切。模型一拆成两个脚本是有道理的模型一 隶属函数.py负责定义每个指标的隶属度曲线模型一 模糊综合评价.py负责合成。这种拆分让隶属函数可以单独调、单独画图验证比塞在一个文件里强。3.2 隶属函数的实现与参数调整常见的隶属函数有三角形、梯形、高斯型。这份代码里我看到的做法是对每个指标定义好、中、差三档用梯形函数过渡import numpy as np def trapezoid(x, a, b, c, d): 梯形隶属函数a,b 为上升沿c,d 为下降沿 if x a or x d: return 0.0 elif b x c: return 1.0 elif a x b: return (x - a) / (b - a) else: return (d - x) / (d - c) # 以赔付率为例低于 0.4 算好0.4-0.6 过渡高于 0.8 算差 x 0.55 print(好档隶属度:, trapezoid(x, 0.0, 0.0, 0.4, 0.6)) print(差档隶属度:, trapezoid(x, 0.6, 0.8, 1.0, 1.0))逻辑说明trapezoid的四个参数a,b,c,d决定了曲线的形状b到c之间是满分区间a到b是上升过渡c到d是下降过渡。参数怎么定我一般会先看数据的分布取分位数当边界——比如赔付率的 25% 分位当b75% 分位当c。如果直接拍脑袋定 0.4、0.6很可能所有样本都落在过渡区综合得分全挤在 0.5 附近区分度就没了。这是模糊评价最常见的翻车点隶属函数参数不贴合数据分布评出来一片中等。3.3 权重确定与综合评价合成权重来自模型二 层次分析.py输出的判断矩阵或者直接用熵权法。合成时用加权平均# 假设有 3 个指标各自隶属度向量和权重 membership np.array([0.8, 0.5, 0.3]) # 三个指标对可持续的隶属度 weights np.array([0.5, 0.3, 0.2]) # 层次分析得到的权重 # 加权合成综合得分 score np.dot(membership, weights) print(综合可持续性得分:, round(score, 4))逻辑说明np.dot做的是加权求和权重之和必须为 1否则得分会超出 0 到 1 的范围。参数上权重向量建议在层次分析里做一致性检验CR 小于 0.1 才认为判断矩阵合理。如果 CR 超标要么调整判断矩阵要么改用熵权法——熵权法完全由数据驱动不需要专家打分适合没有领域专家在场的场景。合成后的得分可以按 0.6、0.4 两个阈值分成可持续、临界、不可持续三档对应到论文里的地区分类。4. 模型二灰色预测与关联分析小样本趋势怎么算4.1 灰色预测 GM(1,1) 的适用边界财产保险数据往往年份少、样本小回归分析容易过拟合灰色预测 GM(1,1) 就是为这种小样本、贫信息场景设计的。它的思路是对原始序列做一次累加生成弱化随机性再用微分方程拟合最后累减还原。模型二 灰色预测.py和figure/GM11.png就是这套流程的产物。但要注意边界GM(1,1) 适合单调趋势明显、数据量在 4 到 10 个点之间的序列。如果你的数据波动剧烈或者有周期性GM(1,1) 会给出很离谱的外推。我见过有人拿它预测月度保费结果因为季节性波动预测值直接飞到天上——这不是代码错是模型选错了。4.2 灰色预测的代码实现与参数import numpy as np def gm11(x0): GM(1,1) 灰色预测x0 为原始序列 x1 np.cumsum(x0) # 一次累加生成 z1 (x1[:-1] x1[1:]) / 2.0 # 紧邻均值生成 B np.column_stack((-z1, np.ones(len(z1)))) Y x0[1:].reshape(-1, 1) # 最小二乘求参数 a, b params np.linalg.inv(B.T B) B.T Y a, b params[0, 0], params[1, 0] # 预测下一个点 x1_pred (x0[0] - b / a) * np.exp(-a * 1) b / a x0_pred x1_pred - x1[-1] return x0_pred, a, b x0 np.array([120, 128, 135, 143, 152], dtypefloat) pred, a, b gm11(x0) print(f发展系数 a{a:.4f}, 灰作用量 b{b:.4f}) print(f下一期预测值: {pred:.2f})逻辑说明np.cumsum做累加生成z1是紧邻均值序列B和Y构成最小二乘的矩阵形式。a叫发展系数反映趋势快慢|a|小于 0.3 时模型精度较高大于 0.5 就要警惕。b是灰作用量代表外部输入。参数上唯一能调的是原始序列的起点——如果去掉最早的异常点预测会稳很多。代码里np.exp(-a * 1)的1是预测步长改成2就是预测两期后但步长越大误差累积越明显一般不超过 3。4.3 灰色关联分析筛因子模型二 灰色关联分析.py用来从一堆候选指标里挑出和可持续性最相关的几个。做法是计算每个指标序列和参考序列的关联系数再取均值排序def grey_relation(ref, compare, rho0.5): 灰色关联度rho 为分辨系数通常取 0.5 ref np.array(ref, dtypefloat) compare np.array(compare, dtypefloat) # 初值化处理消除量纲 ref ref / ref[0] compare compare / compare[0] diff np.abs(ref - compare) min_diff, max_diff diff.min(), diff.max() # 关联系数 xi (min_diff rho * max_diff) / (diff rho * max_diff) return xi.mean() ref [1.0, 1.07, 1.13, 1.19, 1.27] print(赔付率关联度:, round(grey_relation(ref, [1.0, 1.05, 1.12, 1.16, 1.22]), 4)) print(保费增速关联度:, round(grey_relation(ref, [1.0, 1.10, 1.18, 1.30, 1.40]), 4))逻辑说明rho是分辨系数取值在 0 到 1 之间越小则关联系数之间的差异越大一般默认 0.5。初值化是为了消除量纲不然保费金额和增长率放一起比会失真。关联度大于 0.7 通常认为强相关0.5 到 0.7 中等低于 0.5 就可以考虑剔除。这一步的输出直接决定模型一里用哪几个指标所以顺序上应该先跑关联分析再定隶属函数。5. 模型三支持向量机分类、ROC 与 PCA 降维的配合5.1 SVM 分类与数据集结构模型三 支持向量机.py用的是支持向量机数据集.xlsx输出svm_model.pkl和Confusion Matrix.png、ROC.png。SVM 在这里的任务是把地区分成可持续和不可持续两类核函数大概率是 RBF因为保险指标之间往往是非线性关系。import pandas as pd from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.preprocessing import StandardScaler from sklearn.metrics import classification_report, roc_auc_score import joblib df pd.read_excel(data/支持向量机数据集.xlsx) X df.drop(columns[label]).values # 特征列 y df[label].values # 标签列 # 标准化是 SVM 的命门不做的话核函数距离计算会失真 scaler StandardScaler() X_scaled scaler.fit_transform(X) X_train, X_test, y_train, y_test train_test_split( X_scaled, y, test_size0.3, random_state42, stratifyy) model SVC(kernelrbf, C1.0, gammascale, probabilityTrue) model.fit(X_train, y_train) y_pred model.predict(X_test) y_prob model.predict_proba(X_test)[:, 1] print(classification_report(y_test, y_pred)) print(AUC:, round(roc_auc_score(y_test, y_prob), 4)) joblib.dump(model, svm_model.pkl)逻辑说明StandardScaler必须做SVM 基于距离量纲不统一会让某个大数值特征主导结果。C是惩罚系数越大越不容忍误分类容易过拟合gamma控制 RBF 核的影响半径scale是自适应取值。probabilityTrue是为了后面算 ROC 和 AUC不加这个参数predict_proba会报错。stratifyy保证训练测试集类别比例一致小样本时尤其重要。5.2 PCA 降维与 AUC 的权衡figure目录里有一串PCA4,AUC0.99.svg到PCA8,AUC0.63.svg的文件这是作者做的降维实验主成分从 4 个加到 8 个AUC 反而从 0.99 掉到 0.63。这个现象很典型——主成分太少会丢信息太多会把噪声也带进来尤其当样本量小的时候高维空间里 SVM 更容易过拟合。from sklearn.decomposition import PCA for n in [4, 5, 6, 7, 8]: pca PCA(n_componentsn) X_pca pca.fit_transform(X_scaled) Xtr, Xte, ytr, yte train_test_split( X_pca, y, test_size0.3, random_state42, stratifyy) m SVC(kernelrbf, probabilityTrue).fit(Xtr, ytr) auc roc_auc_score(yte, m.predict_proba(Xte)[:, 1]) print(fPCA{n}, AUC{auc:.2f}, 累计方差贡献{pca.explained_variance_ratio_.sum():.3f})逻辑说明explained_variance_ratio_.sum()告诉你保留了多少原始信息一般希望 85% 以上。但 AUC 和方差贡献不一定同向——这份资源里 PCA4 时 AUC 最高说明前 4 个主成分已经抓住了区分两类的主要结构后面几个主成分更多是噪声。参数上n_components不要盲目按累计方差 95%来定要结合下游任务的指标这里是 AUC一起看。这也是这份资源值得拆的地方它把降维维度和分类效果的权衡用图直接摆出来了。6. 避坑与排查复现这套源码最容易踩的五个坑6.1 现象读 Excel 报ImportError: Missing optional dependency openpyxl原因pandas 读.xlsx依赖openpyxl但 pip 装 pandas 时不会自动带上。解决pip install openpyxl如果还报错就pip install xlrd1.2.0处理老式.xls。这个坑几乎每个第一次跑的人都会遇到装完不用改代码。6.2 现象SVM 训练报could not convert string to float原因Excel 里某列混了文本或者标签列是中文是/否。解决先df.dtypes看类型对object列用pd.to_numeric(df[col], errorscoerce)转换标签列用LabelEncoder编码。注意errorscoerce会把无法转换的变成 NaN转换后要检查缺失值数量必要时填充或删行。6.3 现象ROC 曲线画出来是一条对角线AUC 约 0.5原因要么标签和特征错位了要么predict_proba取错了列。解决确认y和X的行对齐predict_proba返回的是两列取[:, 1]才是正类概率。如果标签是 0/1 但正类是 0就要取[:, 0]。这个坑很隐蔽因为代码不报错只是结果没意义。6.4 现象灰色预测结果大得离谱原因原始序列不满足 GM(1,1) 的单调假设或者序列里有零或负数累加后取对数会出问题。解决先画原始序列图看趋势波动大的话改用移动平均预处理或者换用 ARIMA。另外a的绝对值大于 0.5 时预测不可信代码里应该加个判断直接提示。6.5 现象模糊综合评价所有地区得分都在 0.5 附近原因隶属函数参数没贴合数据分布所有样本都落在过渡区。解决用分位数定边界比如b取 25% 分位、c取 75% 分位让样本分散到满分区和过渡区。改完重新画隶属度分布图确认区分度。7. 进阶技巧把三套模型串成一条可复现的流水线单跑每个脚本只能看到局部真正有价值的是把模型一、二、三串起来形成评价—预测—分类的闭环。我的做法是写一个pipeline.py按顺序调用各模块中间结果落盘方便回溯import subprocess import pandas as pd steps [ (模型二 灰色关联分析.py, 筛选关键因子), (模型一 隶属函数.py, 构造隶属度), (模型一 模糊综合评价.py, 输出可持续性得分), (模型二 灰色预测.py, 预测未来趋势), (模型三 支持向量机.py, 训练分类模型), ] for script, desc in steps: print(f 执行 {desc}: {script}) result subprocess.run( [python, fcode/{script}], capture_outputTrue, textTrue) if result.returncode ! 0: print(f失败: {result.stderr[:200]}) break print(完成)逻辑说明subprocess.run逐个调脚本capture_outputTrue捕获输出便于排查returncode非零就中断避免错误累积。参数上可以把每个脚本的输出统一存到一个output/目录用时间戳命名这样调参时能对比不同版本的结果。验证方法上我一般会做两件事一是把svm_model.pkl重新加载用同一批测试数据预测确认 AUC 和训练时一致排除保存加载的坑二是对灵敏度分析.xlsx里的参数做 ±10% 扰动看综合得分排序是否稳定如果排序大幅变化说明模型对某个参数过于敏感结论就不够稳健。从那以后我每次拿到这种多模型源码包都强制先跑一遍数据体检和依赖检查再按关联分析→评价→预测→分类的顺序串起来绝不跳步。这套流程帮我省下了大量在报错里打转的时间。希望这份拆解能帮你把这份 2024 MCM/ICM E 题源码真正跑起来、用起来。本文还有配套的精品资源点击获取