
简介这是一份面向数据科学初学者与保险行业数据分析人员的健康保险理赔预测实战资源。基于Kaggle医疗费用个人数据集围绕年龄、性别、BMI、子女数、吸烟状况与居住地区等特征使用线性回归、Ridge、Lasso、ElasticNet以及线性/多项式/高斯核SVR等模型分别建模预测个人医疗理赔支出并配有特征相关性可视化分析适合回归建模练习与特征工程入门。资源包共30个文件包含11个训练好的模型文件pkl格式、10张特征与预测结果可视化图png、7个Python源码脚本、1个CSV数据集以及1份说明文档整体仅1.25MB便于快速下载与本地运行。目前已有781人学习浏览适合需要参考完整建模流程的读者。内容覆盖数据读取、可视化探索、模型训练、评估与对比的完整流程源码中包含可视化分析模块、train/test划分、模型比较脚本可直接运行并复现实验结果。通过箱线图、散点矩阵等图形可直观理解BMI、吸烟、年龄等因素对理赔支出的影响。读者既能获得可直接调用的预测模型也能学习多种回归算法在保险费用预测场景中的选择与调优思路对保险定价、健康管理数据分析也有实用参考价值。1. 健康保险理赔预测到底在预测什么每个做保险数据分析的人都会遇到同一个问题理赔费用不是算出来的而是估出来的。健康保险的理赔支出受投保人的年龄、BMI、生活习惯、既往病史等多因素影响不存在严格的函数关系但存在着可学习的统计规律。用 Python 做理赔支出预测核心任务是拿一份带有历史理赔记录的数据集通过特征数据可视化找到影响费用的关键变量再训练一个线性回归模型让模型对新人该收多少保费、准备多少理赔准备金给出量化参考。这个流程在精算、核保和健康管理场景里都通用也是机器学习入门最常见的落地练习之一。本文按一条完整链路走先分析数据长什么样、字段意味着什么再做特怔工程然后用 scikit-learn 训练线性回归模型最后给出评估指标和实战调参细节。数据用公开的健康保险理赔数据集字段包括年龄、性别、BMI、子女数、是否吸烟、地区以及个人年理赔费用足够支撑可视化分析和回归建模不涉及任何隐私信息。2. 理赔数据的特征可视化分析与字段语义拆解2.1 先搞清楚理赔数据集的字段结构拿到一个理赔数据集第一步不是跑模型而是用info()和head()确认数据质量。健康保险理赔数据通常包含七个核心字段每个字段的语义直接影响后续特征工程的方向。import pandas as pd import numpy as np df pd.read_csv(insurance.csv) print(df.shape) print(df.info()) print(df.head())上面代码中df.shape输出 (1338, 7)代表 1338 条理赔记录、7 个特征列。df.info()能快速检查有没有空值df.head()看前五行的数据分布。逻辑上先做这三个动作能避免后面建模时因为数据缺失或格式问题返工。这个数据集的七个字段中charges是目标变量也就是个人年度理赔金额。年龄、BMI、子女数属于数值特征性别、是否吸烟、地区属于类别特征。一个容易被忽略的细节是BMI 和年龄之间往往存在交互作用而吸烟状态对理赔金额的影响强度远超其他特征这一点在可视化阶段会非常明显。2.2 用 seaborn 做理赔分布与相关性热力图特征数据可视化是整个项目中最直观的一步。通过画分布图、箱线图和热力图能在建模前就对哪些特征值得进入模型有基本判断。import matplotlib.pyplot as plt import seaborn as sns plt.figure(figsize(12, 6)) plt.subplot(1, 2, 1) sns.histplot(df[charges], bins50, kdeTrue) plt.title(理赔金额分布) plt.xlabel(charges) plt.subplot(1, 2, 2) sns.boxplot(xsmoker, ycharges, datadf) plt.title(吸烟状态与理赔金额的关系) plt.tight_layout() plt.show() numeric_cols df.select_dtypes(include[np.number]).columns.tolist() plt.figure(figsize(8, 6)) sns.heatmap(df[numeric_cols].corr(), annotTrue, cmapcoolwarm) plt.title(数值特征相关性热力图) plt.show()左图histplot显示理赔金额呈严重右偏分布——多数人理赔金额集中在低区间少数高额理赔把均值拉高。右图boxplot是最关键的发现吸烟人群的理赔金额中位数和四分位距远高于非吸烟人群这一特征基本可以断定是模型的主力变量。相关性热力图输出的是数值特征之间的皮尔逊相关系数。年龄与理赔金额呈正相关约 0.30BMI 与理赔金额呈弱正相关约 0.20吸烟作为二分类变量如果先编码再计算相关往往能达到 0.75 以上。这说明线性回归模型只要选对特怔即便不做复杂的非线性变换也能拿到可用的精度。2.3 从可视化结果反推特征筛选策略观察完图表后应该形成一条明确的分析路径。理赔金额右偏意味着直接用原始值做线性回归会被极端值带偏常见的处理手段是取对数变换。吸烟状态需要编码后参与计算同时考虑把它和年龄、BMI 做交互特征比如吸烟且 BMI 超标这类组合条件。类别特征的取值也需要关注。地区字段分为东北部、东南部、西北部、西南部从数据上看东南部的平均理赔金额略高但这种差异可能由吸烟人数比例引起而不是地区本身需要通过回归系数来验证净效应。性别字段在多数分析中与理赔金额相关性很弱建模时可以保留也可以丢弃对模型精度影响不大。3. 线性回归前的特征工程与数据预处理3.1 缺失值处理与异常值截断实际业务数据通常不像公开数据集那么干净所以特征工程的第一件事是明确缺失值和异常值的处理策略。用isnull().sum()可以逐列统计缺失数量对于健康保险数据缺失率低于 5% 的字段用中位数填充即可超过 5% 的字段要评估是否该删除。异常值在理赔数据里不能一律删除。高额理赔本身就是保险业务里的重要抽样对象删除会直接削弱模型的预测上限。常见的做法是用quantile()计算 99% 分位做截断或者保留异常值但用 log1p 变换压缩它的影响范围。from sklearn.model_selection import train_test_split from sklearn.preprocessing import StandardScaler, OneHotEncoder from sklearn.compose import ColumnTransformer from sklearn.pipeline import Pipeline df[log_charges] np.log1p(df[charges]) X df.drop([charges, log_charges], axis1) y df[log_charges] X_train, X_test, y_train, y_test train_test_split( X, y, test_size0.2, random_state42 ) print(f训练集样本数: {X_train.shape[0]}, 测试集样本数: {X_test.shape[0]})np.log1p对理赔金额做对数压缩log1p是log(1x)的数值稳定版本能直接处理取对数后可能出现的问题而且后续可以用expm1反转回原始金额量级。train_test_split按 8:2 拆分数据random_state42固定随机种子保证每次运行结果可复现。3.2 类别特征编码与数值特征标准化线性回归对特征尺度敏感吗严格说线性回归本身不需要标准化但当你使用正则化版本Lasso、Ridge时特征量纲差异会造成惩罚不均所以这里统一走标准化流程。类别特征一律做 one-hot 编码注意dropfirst参数可以避免多分类变量产生的多重共线性问题。numeric_features [age, bmi, children] categorical_features [sex, smoker, region] numeric_transformer Pipeline(steps[ (scaler, StandardScaler()) ]) categorical_transformer Pipeline(steps[ (onehot, OneHotEncoder(dropfirst)) ]) preprocessor ColumnTransformer( transformers[ (num, numeric_transformer, numeric_features), (cat, categorical_transformer, categorical_features) ] ) model Pipeline(steps[ (preprocessor, preprocessor), (regressor, LinearRegression()) ])ColumnTransformer的作用是按列分别执行不同的预处理逻辑数值列做标准化、类别列做独热编码最后拼接成完整的特征矩阵。用 Pipeline 把预处理和模型包在一起之后调用fit和predict时不需要单独管理每一步的中间状态交叉验证时也不会因为遗漏某一步而报错。3.3 特征矩阵构建后要检查的东西特征工程做完输出矩阵的列数会发生变化。原始 6 个特征经过 one-hot 编码后变成了 8 列左右具体取决于地区字段的取值数量。可以用model.named_steps[preprocessor].transform(X_train).shape确认当前矩阵的维度避免后面传入模型时报特征数量不一致的错误。另一个容易被忽略的点是特征顺序。ColumnTransformer内部会按 transformers 列表的顺序拼接所以如果你在手动同步训练集和测试集的特征顺序这步最容易出错。用 Pipeline 统一管理后顺序问题自动解决。4. 用线性回归模型建立理赔支出预测4.1 管线内训练与基础评估指标完成预处理管线搭建后直接调fit就可以得到训练好的模型。评估回归模型看三个指标R² 表示模型解释了目标变量多少比例的方差MAE 是平均绝对误差RMSE 因为对大误差取平方所以更敏感。对于理赔数据RMSE 通常比 MAE 大很多这是右偏分布的典型特征。from sklearn.linear_model import LinearRegression from sklearn.metrics import r2_score, mean_absolute_error, mean_squared_error model.fit(X_train, y_train) y_pred_log model.predict(X_test) y_pred np.expm1(y_pred_log) y_test_original np.expm1(y_test) r2 r2_score(y_test_original, y_pred) mae mean_absolute_error(y_test_original, y_pred) rmse np.sqrt(mean_squared_error(y_test_original, y_pred)) print(fR² {r2:.4f}) print(fMAE {mae:.2f}) print(fRMSE {rmse:.2f})代码将预测结果先用expm1从对数空间映射回原始理赔金额再计算评估指标。这样做的好处是评估结果和业务口径一致——业务关心的是预测费用和实际费用差多少美元而非对数值差多少。r2_score对线性回归来说是最直观的解释力度指标如果 R² 低于 0.7说明特征组合还有优化空间。4.2 回归系数解读与业务含义线性回归模型在保险场景中的一大优势是可解释性。coef_系数表能直接回答吸烟对理赔支出的边际影响是多少这类业务问题。feature_names (numeric_features list(model.named_steps[preprocessor] .named_transformers_[cat] .named_steps[onehot] .get_feature_names_out(categorical_features))) coefficients pd.DataFrame({ feature: feature_names, coefficient: model.named_steps[regressor].coef_ }) print(coefficients.sort_values(coefficient, keynp.abs, ascendingFalse))上一步代码把预处理后的特征名列和回归系数组装成表格按系数绝对值排序。注意从OneHotEncoder获取列名时get_feature_names_out会输出类似smoker_yes、region_southeast的格式与原始列名一一对应。由于特征先做了标准化这些系数的含义是当这个特征变化一个标准差理赔金额的对数值平均变动多少个单位。吸烟特征的系数通常在 1.5 以上转换成实际金额意味着吸烟者的理赔支出中位数是非吸烟者的 4 倍左右。而性别特征的系数接近 0可以视为没有预测能力。4.3 残差分析与模型诊断评估模型不能只看 R²残差分析能暴露线性回归的假设违反问题。如果残差随预测值增大而增大说明目标变量仍未充分正态化可能需要更强的变换比如 Box-Cox。常见做法是画出y_pred对残差的散点图。residuals y_test_original - y_pred plt.figure(figsize(8, 5)) sns.scatterplot(xy_pred, yresiduals, alpha0.6) plt.axhline(y0, colorred, linestyle--) plt.xlabel(预测理赔金额) plt.ylabel(残差) plt.title(残差分布图) plt.show()残差图上如果点大致均匀分布在 y0 水平线两侧说明模型没有明显的系统偏差。如果出现漏斗形分布——右边散得更开说明高理赔段的预测误差被低估了。这种场景下单靠线性回归是不够的通常的做法是引入分位数回归或者对高理赔段单独建模。5. 线性回归在理赔预测中的三个进阶落地技巧5.1 用 Ridge 和 Lasso 处理共线性与特征选择理赔数据集的 one-hot 编码变量容易引入共线性普通最小二乘的系数方差会被放大导致测试集预测不稳定。把LinearRegression换成Ridge或Lasso可以在 Pipeline 里改一行代码完成切换。from sklearn.linear_model import Ridge, Lasso ridge_model Pipeline(steps[ (preprocessor, preprocessor), (regressor, Ridge(alpha1.0)) ]) lasso_model Pipeline(steps[ (preprocessor, preprocessor), (regressor, Lasso(alpha0.01)) ])alpha是正则化强度值越大惩罚力度越强。Lasso 会把弱特征的系数压到 0起到自动特征选择的作用。实践中先跑一遍 Lasso 看哪些特征系数为 0再用 Ridge 做最终模型是效率比较高的组合方式。5.2 用交叉验证替代单次切分评估train_test_split的结果受随机种子影响单次评估会有偶然性。改用cross_val_score做 5 折交叉验证取 R² 均值和标准差能更客观地反映模型在不同数据子集上的表现。from sklearn.model_selection import cross_val_score cv_scores cross_val_score(model, X, y, cv5, scoringr2) print(f5折交叉验证 R²: {cv_scores.mean():.4f} ± {cv_scores.std():.4f})交叉验证再把参数网格搜索加进来用GridSearchCV同时搜索alpha和编码器参数基本就是工业基线模型的完整套路了。但要注意交叉验证的对象如果是对数变换后的目标变量最终评估也要保持一致不要在变换和目标变量之间混用。5.3 预测结果按理赔段位分层验证最后一个建议是不要把所有预测误差混在一起看。把测试集按实际理赔金额分成低、中、高三档分别计算 MAE 和 RMSE。通常你会发现低分段 MAE 很小、高分段误差极大这说明模型在常规理赔上准、在极端理赔上弱。对精算或风控场景而言高分段误差才是真正的风险敞口。常见做法是用残差分布的标准差设定理赔准备金的安全边际或者对高分段单独训练一个回归模型。这样至少从单模型走天下进阶到了按风险分层做配额已经接近实际精算建模的思路了。本文还有配套的精品资源点击获取