1. 从赛题到模型:一次真实的财产保险建模实战复盘
去年带队打美赛E题的经历,现在回想起来依然觉得信息量巨大。题目聚焦财产保险的可持续性,说白了,就是给保险公司建个模型,预测未来会不会赔穿,以及怎么定价才能既赚钱又稳当。这玩意儿听起来是金融精算的活儿,但美赛的魅力就在于,它把问题抽象成了一个典型的“数据驱动决策”问题。我们当时核心用了两种方法:多准则决策分析(MCDA)来搭建评估框架和进行方案排序,用随机森林(Random Forest)来做核心的风险预测和关键因子挖掘。网上很多思路分享要么只讲理论,要么只丢代码,缺了中间最关键的“为什么这么选”以及“怎么把模型结果用起来”的桥段。这篇复盘,我就结合那次实战,把从理解问题、选择方法、到代码实现、结果解读的全链路掰开揉碎讲清楚,特别是MCDA和随机森林在这个场景下是怎么“打配合”的。
2. 问题拆解:保险可持续性到底在问什么?
美赛E题通常不会直接让你算保费,它会把问题包装在一个更宏观的叙事里。那年题目大致是:评估财产保险(特别是应对极端天气事件的)的长期可持续性,并探讨可能的策略(如保费调整、风险共担、政府补贴等)。第一步不是急着找数据跑模型,而是把“可持续性”这个模糊的目标,翻译成可量化的建模目标。
2.1 定义核心决策目标与评价准则
可持续性不是一个单一指标。我们团队当时通过大量阅读背景材料(题目会提供一些参考文献线索),把它分解为三个核心维度,这也是后续MCDA的基石:
- 财务稳健性:保险公司不能破产。这可以量化为核心指标,如:偿付能力充足率(模拟未来的赔付支出与资本金)、长期平均承保利润率、破产概率(在极端情景下的模拟)。这部分需要预测未来的赔付。
- 社会可负担性:保费不能高到让居民买不起保险,失去保障意义。可量化指标如:保费收入占地区居民收入的中位数比例、保险渗透率的变化。
- 风险减量有效性:保险不能只是事后赔钱,应该能激励或支持事前防灾减灾。这部分较难量化,但我们尝试用指标如:保费折扣与防灾措施挂钩的参保比例、保险赔付资金中用于灾后重建加固的比例(假设)。
仅仅有这三个维度还不够,题目要求评估“不同策略”。所以,我们定义了四到五个待评估的策略方案,例如:方案A(激进市场价)、方案B(温和涨价+免赔额提高)、方案C(政府再保险兜底)、方案D(社区风险共担池)。
于是,我们的问题就转化为了一个经典的多准则决策问题:在“财务稳健性”、“社会可负担性”、“风险减量有效性”这三个准则(Criteria)下,比较A、B、C、D这几个方案(Alternatives)的优劣,并给出排序或推荐。这就是引入MCDA的动机。
2.2 数据需求与处理难点
要支撑上述评估,尤其是财务稳健性的预测,我们需要数据。理想数据包括:历史灾害损失数据、地区财产价值分布、保单信息、气候预测数据等。美赛通常只提供有限数据或指引你寻找公开数据。我们当时的策略是:
- 核心驱动数据:使用公开的历史飓风/洪水损失数据(如美国NOAA的数据库)和地区化的人口、财产GDP数据作为风险暴露度。
- 关键处理:将大区域数据降尺度到更小的评估单元(如县级别),这里就用到了简单的空间插值或按比例分配。
- 构建特征:对于每个评估单元,我们构造了用于预测未来损失的特征,例如:历史平均损失、暴露价值(财产总值)、到海岸线距离、海拔中位数、气候预测的极端降水指数变化率等。这就是随机森林模型的输入特征(X)。
- 目标变量(Y):我们设定为“未来特定年份的期望损失率(损失/暴露价值)”。由于没有真实未来数据,我们采用了一种模拟方法:用历史损失数据拟合一个分布(例如伽马分布或广义帕累托分布,用于刻画极端值),然后根据气候预测趋势调整该分布的参数,生成多条可能的未来损失情景。这样,我们就得到了一个包含多个样本(不同评估单元、不同模拟情景)的训练数据集。
注意:这里是一个巨大的简化点,也是建模的“艺术”所在。真实精算模型复杂得多,但在数模竞赛72小时内,必须做出合理且可解释的假设,并明确写在论文中。
3. 模型核心一:随机森林预测未来风险
随机森林不是黑箱,在这个场景下,我们看重它两个不可替代的优点:1) 能处理特征间的复杂非线性关系;2) 能给出特征重要性排序,告诉我们哪些因素对损失预测影响最大,这本身就是极具价值的洞察。
3.1 模型训练与调参实战
我们用的是scikit-learn的RandomForestRegressor来预测连续值的“损失率”。代码骨架如下,但重点是参数背后的思考:
import pandas as pd import numpy as np from sklearn.ensemble import RandomForestRegressor from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import mean_squared_error, r2_score # 假设 df 是准备好的DataFrame,包含特征列和‘loss_ratio’目标列 X = df.drop(columns=['loss_ratio', 'region_id']) # 特征 y = df['loss_ratio'] # 目标变量 # 划分训练集和测试集 X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42) # 初始化随机森林模型 rf = RandomForestRegressor(random_state=42, n_jobs=-1) # n_jobs=-1 用上所有CPU核心 # 关键参数网格搜索 param_grid = { 'n_estimators': [100, 200, 300], # 树的数量:太少欠拟合,太多计算慢且可能过拟合 'max_depth': [10, 20, 30, None], # 树的最大深度:控制模型复杂度,None表示不限制,容易过拟合 'min_samples_split': [2, 5, 10], # 内部节点再划分所需最小样本数:值越大,树越简单 'min_samples_leaf': [1, 2, 4], # 叶节点最小样本数:同上,平滑模型 'max_features': ['sqrt', 'log2'] # 寻找最佳分割时考虑的特征数:经典设置,防止过拟合 } # 网格搜索交叉验证 grid_search = GridSearchCV(estimator=rf, param_grid=param_grid, cv=5, scoring='neg_mean_squared_error', verbose=1) grid_search.fit(X_train, y_train) # 输出最佳参数 print("Best Parameters:", grid_search.best_params_) best_rf = grid_search.best_estimator_ # 在测试集上评估 y_pred = best_rf.predict(X_test) mse = mean_squared_error(y_test, y_pred) r2 = r2_score(y_test, y_pred) print(f"Test MSE: {mse:.4f}") print(f"Test R^2: {r2:.4f}")调参心得:
n_estimators:在计算资源允许下,大一点好(我们选了300),因为随机森林是“集大成者”,树越多越稳定。可以用learning_curve观察误差是否已收敛。max_depth:我们最终选择了20,而不是None。因为我们的特征数量有限(10个左右),且数据有噪声,限制深度可以有效防止对历史噪声的过拟合,增强模型泛化到未来情景的能力。max_features:选择'sqrt'(特征数的平方根)。这是分类问题的常见默认值,对于回归问题也适用,它能保证每棵树有足够的差异性,这是集成学习效果好的关键。
3.2 特征重要性分析与业务解读
模型训练好后,预测只是第一步。更重要的是利用随机森林内置的特征重要性分析。
# 获取特征重要性 importances = best_rf.feature_importances_ feature_names = X.columns indices = np.argsort(importances)[::-1] # 降序排列 # 打印重要性排序 print("Feature ranking:") for f in range(X.shape[1]): print(f"{f + 1}. {feature_names[indices[f]]} ({importances[indices[f]]:.4f})") # 可视化 import matplotlib.pyplot as plt plt.figure(figsize=(10, 6)) plt.title("Feature Importances") plt.bar(range(X.shape[1]), importances[indices], align="center") plt.xticks(range(X.shape[1]), [feature_names[i] for i in indices], rotation=45, ha='right') plt.tight_layout() plt.show()我们当时的发现:历史平均损失和暴露价值的重要性最高,这符合直觉。但排第三的是气候预测的极端降水指数变化率,而非到海岸线距离。这给了我们一个关键论据:在未来风险评估中,气候变化因子的影响权重正在提升,甚至可能超过某些静态地理因素。这个结论直接支撑了我们后续在策略评估中,强调方案必须包含对气候长期变化的适应性。
3.3 预测结果用于MCDA输入
对于每一个评估单元(县),我们用训练好的最佳随机森林模型,预测其在未来某个时间窗口(如2050年)下的“期望损失率”。然后,将这个损失率乘以该单元的“暴露价值”,就得到了预测的期望赔付额。
对于每一个待评估的策略方案(A/B/C/D),我们根据其规则(如保费变化、免赔额变化、政府分担比例),调整模型的输入或对输出进行后处理。例如:
- 方案B(提高免赔额):在计算保险公司实际赔付时,将预测的损失额减去免赔额部分(设定一个阈值)。
- 方案C(政府再保险):当预测损失超过某个巨灾阈值时,超过部分按一定比例(如80%)从损失中扣除,模拟政府承担。
这样,对于每一个方案,我们都能得到一套新的、模拟未来的财务指标(如赔付成本、净保费收入),这些指标将成为MCDA中“财务稳健性”准则下的具体量化值。
4. 模型核心二:MCDA综合评估与策略排序
有了随机森林提供的量化基础,MCDA就登场了。它的任务是把不同维度(准则)、不同量纲的指标,综合起来,给方案排个座次。我们选用的是层次分析法(AHP)与TOPSIS结合的路径,因为AHP适合确定准则权重(需要主观判断),而TOPSIS适合对方案进行客观排序。
4.1 利用AHP确定准则权重
财务稳健性、社会可负担性、风险减量,这三个准则哪个更重要?这没有标准答案,但需要一套自洽的逻辑。我们通过查阅文献和内部讨论,构建了判断矩阵:
准则比较矩阵 (1-9标度法): 财务稳健性 社会可负担性 风险减量 财务稳健性 1 3 5 社会可负担性 1/3 1 3 风险减量 1/5 1/3 1(解读:我们认为财务稳健性比社会可负担性稍微重要一点(3),比风险减量明显重要(5);社会可负担性比风险减量稍微重要一点(3)。)
import numpy as np # 定义判断矩阵 judgment_matrix = np.array([ [1, 3, 5], [1/3, 1, 3], [1/5, 1/3, 1] ]) # 计算权重(特征向量法) def ahp_weight(matrix): # 计算每列的几何平均数 geom_mean = np.prod(matrix, axis=1) ** (1.0 / matrix.shape[1]) # 归一化得到权重 weights = geom_mean / np.sum(geom_mean) return weights weights = ahp_weight(judgment_matrix) print("AHP计算得到的准则权重:") print(f"财务稳健性: {weights[0]:.3f}") print(f"社会可负担性: {weights[1]:.3f}") print(f"风险减量有效性: {weights[2]:.3f}") # 一致性检验(略,但论文中必须展示并满足CR<0.1)计算后,我们得到的权重可能是:财务稳健性 0.65,社会可负担性 0.25,风险减量有效性 0.10。这反映了我们的核心判断:保险公司先要活下来(财务稳健),才能谈社会责任。
4.2 构建决策矩阵与TOPSIS排序
接下来,我们需要每个方案在每个准则下的得分。财务稳健性准则下的得分,来源于随机森林模型模拟出的财务指标(如净利润的现值),我们将其归一化到效益型指标(越大越好)。社会可负担性可能用保费负担率(越小越好,需转化为成本型指标处理)。风险减量有效性我们用假设的评分(1-10分)。
假设我们得到如下决策矩阵(数据已做归一化处理,且统一为效益型,即数值越大越好):
| 方案 | 财务稳健性 (权重0.65) | 社会可负担性 (权重0.25) | 风险减量 (权重0.10) |
|---|---|---|---|
| 方案A | 0.90 | 0.40 | 3 |
| 方案B | 0.75 | 0.70 | 7 |
| 方案C | 0.60 | 0.85 | 6 |
| 方案D | 0.80 | 0.60 | 8 |
import numpy as np # 决策矩阵 (行:方案, 列:准则) decision_matrix = np.array([ [0.90, 0.40, 3], [0.75, 0.70, 7], [0.60, 0.85, 6], [0.80, 0.60, 8] ]) weights = np.array([0.65, 0.25, 0.10]) # AHP得到的权重 # 1. 加权规范化决策矩阵 norm_matrix = decision_matrix / np.sqrt((decision_matrix ** 2).sum(axis=0)) # 向量归一化 weighted_norm_matrix = norm_matrix * weights # 2. 确定理想解和负理想解 ideal_best = weighted_norm_matrix.max(axis=0) # 每个准则的最大值 ideal_worst = weighted_norm_matrix.min(axis=0) # 每个准则的最小值 # 3. 计算各方案到理想解和负理想解的距离 dist_to_best = np.sqrt(((weighted_norm_matrix - ideal_best) ** 2).sum(axis=1)) dist_to_worst = np.sqrt(((weighted_norm_matrix - ideal_worst) ** 2).sum(axis=1)) # 4. 计算相对贴近度 closeness = dist_to_worst / (dist_to_best + dist_to_worst) # 5. 排序 scheme_names = ['方案A', '方案B', '方案C', '方案D'] ranking = np.argsort(closeness)[::-1] # 降序排列,贴近度越大越好 print("TOPSIS相对贴近度及排序:") for i, idx in enumerate(ranking): print(f"第{i+1}名: {scheme_names[idx]} (贴近度: {closeness[idx]:.4f})")结果解读:在我们的假设数据下,可能方案B或D会胜出,因为它们在不同准则间取得了更好的平衡。方案A虽然财务上好,但社会可负担性太差;方案C社会可负担性好但财务表现弱。TOPSIS的结果给出了一个量化的综合排序。在论文中,我们必须对权重的敏感性进行分析,即如果权重发生变化(例如,决策者更看重社会公平),排序结果是否会改变?这能体现模型的鲁棒性和决策的灵活性。
5. 全流程集成、论文呈现与避坑指南
模型跑通只是完成了技术部分,如何将其整合成一个有说服力的故事,并体现在论文中,是拿奖的关键。
5.1 模型链条的串联与可视化
在论文的“模型”部分,我们需要画一个清晰的流程图,展示从数据到最终决策的完整链条:
[历史数据 + 气候预测] -> (特征工程) -> [随机森林模型] -> (预测未来损失) -> [财务模拟器] -> (生成各方案财务指标) -> [MCDA评估矩阵] -> (AHP确定权重 + TOPSIS排序) -> [策略推荐]这个图能让评委一眼看懂你的建模逻辑。
5.2 结果可视化与故事线
- 随机森林部分:展示特征重要性柱状图;用地图展示不同区域预测的未来风险变化(热力图);对关键区域进行损失分布的模拟(箱线图或概率密度图)。
- MCDA部分:展示准则权重的雷达图或条形图;用TOPSIS的贴近度绘制方案排序的条形图;制作敏感性分析的表格或线图,展示权重变化时排序的稳定性。
- 故事线:论文的摘要和引言就要点明“我们用一个数据预测模型(RF)驱动一个多目标决策模型(MCDA)来解决保险可持续性问题”。在分析部分,先讲风险预测发现了什么(如气候因子重要性上升),再讲基于此的财务模拟结果,最后讲综合权衡下的策略选择。结论要回应题目所有要求,并提出具体、可操作的建议。
5.3 实战中踩过的坑与应对策略
- 数据尺度不一致:历史损失数据可能是州级别的,但财产暴露数据是县级别的。直接合并会出问题。我们采用按财产价值比例进行分配的方法,并在论文中说明了这一假设及其局限性。
- 随机森林过拟合:初期模型在训练集上R²很高,但模拟未来情景时波动巨大。通过交叉验证、限制树深度(max_depth)、增加
min_samples_leaf来增加正则化,并最终使用OOB(Out-of-Bag)误差作为泛化能力的参考。 - MCDA权重主观性被挑战:这是AHP方法的固有缺点。应对方法是:a) 引用相关文献支持我们的权重判断;b) 进行广泛的敏感性分析,展示当权重在合理范围内变动时,我们的核心结论(例如方案B和D始终优于A和C)是否依然成立。这反而成了模型稳健性的证明。
- 计算时间过长:随机森林网格搜索加上对多个方案、多个情景的模拟,计算量很大。我们提前将数据预处理和特征工程写好脚本,在性能好的电脑上运行。并在论文中注明“所有模拟均在配备XX处理器的计算机上完成,总计算时间约X小时”,体现实操可行性。
- 忽略模型不确定性:只给出一个点预测(期望损失)是不够的。我们利用随机森林可以输出预测区间的特性(如用
sklearn的quantile_forest或自助法),展示了未来损失的置信区间,并在财务模拟中进行了压力测试(例如,采用95%分位数的损失),让评估更稳健。
这次美赛E题的建模经历,本质上是一次标准的“数据科学解决商业问题”的演练。随机森林提供了强大的预测能力和因子洞察,而MCDA则提供了一个将复杂、多目标的业务问题结构化的决策框架。两者的结合,使得模型既有数据驱动的客观性,又能容纳决策者的主观价值判断。代码和公式只是工具,真正的核心在于你如何定义问题、如何解释结果、如何将一个复杂的现实世界问题,拆解、转化并封装进这些工具里,最后讲出一个逻辑自洽、有洞察力的故事。这或许才是数学建模竞赛,乃至之后解决真实世界问题,最需要打磨的能力。