ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

保险费用预测:20个Python脚本拆解完整回归建模流程

保险费用预测:20个Python脚本拆解完整回归建模流程 简介这是一份面向机器学习初学者的完整实战案例围绕个人健康保险费用数据集讲解回归建模与预测分析的完整流程。压缩包共22个文件包含20个Python源代码、1个CSV数据文件和1个readme说明整体大小58KB。代码覆盖探索性数据分析、特征工程、统计检验、多项式回归、正则化、随机森林、SVR、XGBoost、模型评估与超参数搜索等环节使用numpy、pandas、matplotlib、seaborn、scikit-learn、xgboost、statsmodels、bokeh等常用库按数字编号排布便于从EDA到建模循序渐进。所有代码均手工整理无语法错误可直接运行适合在Jupyter Notebook等环境中边学边练通过单步执行加深理解。已有77人学习浏览从该资源中可一次获得多套模型对比方案、数据预处理脚本、可视化代码及调参思路能帮助理解特征对保费的影响并学会评估模型泛化能力。1. 保险费用预测20 个 Python 脚本背后的完整建模路径个人健康保险费用数据集Medical Cost Personal Dataset是机器学习入门阶段最常被拿来练手的表格型数据集之一。它的规模不大——1338 条记录、7 个字段数据体积仅有 54.32 KB但正因为小它非常适合用来完整走一遍探索性数据分析EDA→ 特征工程 → 模型训练 → 超参数调优 → 结果评估的建模闭环。我拆解这份包含 20 个源代码文件的资源包时发现它覆盖了线性回归、Ridge、Lasso、ElasticNet、SVR、随机森林、XGBoost、决策树共 8 类回归模型且每个脚本独立可运行实验痕迹完整。这套代码的参考价值在于它能让你在真实业务数据上对比不同模型的 R² 表现理解为什么线性模型在保险费用预测中依然有竞争力以及多项式特征、正则化、Box-Cox 变换等技巧对回归任务的实际影响。适合人群有两类一是正在学习机器学习但停留在理论、缺乏完整项目代码参考的初学者二是需要快速搭建回归基线模型的从业者可以用这套代码作为起点做二次改造。下面我按建模顺序拆解这套资源的关键实现。2. EDA 与统计检验建模前必须完成的四步探查2.1 数据概览与缺失值排查资源包中的8-Medical Cost Personal Datasets.py和10-Exploratory Data Analysis EDA.py负责数据加载与基础探查。常见做法是先看 shape、dtypes、describe() 结果确认数据类型分布和数值范围。以下代码对应资源包中的核心逻辑import pandas as pd import numpy as np df pd.read_csv(insurance.csv) print(数据集形状:, df.shape) print(\n数据类型:\n, df.dtypes) print(\n描述性统计:\n, df.describe().T) print(\n缺失值统计:\n, df.isnull().sum())代码说明shape输出行数和列数dtypes判断字段类型describe().T转置后更便于查看数值列的均值、标准差、最小值、四分位数和最大值。保险数据集本身无缺失值但保留这段代码的价值在于后续替换数据时可以直接复用检测逻辑。isnull().sum()逐列返回缺失数量是建模前必须执行的第一步。2.2 目标变量分布与偏度处理11-Statistical Analysis of Medical Cost Datasets.py中包含对 charges费用字段的分布分析其中使用了scipy.stats.skew和kurtosis计算偏度与峰度。保险费用数据通常呈现右偏分布——大多数人费用在 5000 到 15000 之间但少数高额理赔会把右尾拉得很长。这种分布会让线性回归的残差不满足正态性假设直接影响模型的拟合效果。from scipy.stats import skew, kurtosis, boxcox import numpy as np charges df[charges] print(f偏度: {skew(charges):.3f}) print(f峰度: {kurtosis(charges):.3f}) # Box-Cox 变换处理右偏 transformed_charges, lambda_value boxcox(charges 1) # 1 避免零值 print(fBox-Cox 最优 lambda: {lambda_value:.3f})代码说明skew计算偏度绝对值大于 0.5 即认为存在明显偏斜kurtosis大于 3 说明分布比正态分布更尖峰。boxcox是 scipy 提供的 Box-Cox 幂变换函数它自动搜索最优 lambda 使变换后的数据更接近正态分布。注意这里对 charges 加了 1 再变换因为 Box-Cox 要求输入必须为正数。变换后训练模型预测时需要做逆变换还原np.expm1(transformed_predictions / lambda_value)或使用scipy.special.inv_boxcox。2.3 多重共线性诊断VIF 计算15-Medical_Cost_Prediction.py中用到了statsmodels.stats.outliers_influence.variance_inflation_factor——这是方差膨胀因子VIF的计算接口。在保险费用的回归建模中bmi、age、children 等数值型特征之间可能存在相关性而 VIF 能定量衡量每个特征被其他特征解释的程度。from statsmodels.stats.outliers_influence import variance_inflation_factor # 选取数值型特征 num_features [age, bmi, children] X_num df[num_features].copy() # 添加常数项VIF 计算需要截距 import statsmodels.api as sm X_with_const sm.add_constant(X_num) vif_data pd.DataFrame() vif_data[feature] X_with_const.columns vif_data[VIF] [variance_inflation_factor(X_with_const.values, i) for i in range(X_with_const.shape[1])] print(vif_data)参数说明variance_inflation_factor(exog, exog_idx)第一个参数是包含常数项的特征矩阵第二个参数是特征所在列索引。VIF 大于 10 通常认为存在严重多重共线性需要删除或合并特征5 到 10 之间需要结合业务判断。在这个数据集中age、bmi、children 的 VIF 一般较低说明共线性不严重但加上 region、smoker 等类别变量的编码后情况会变化这需要在特征工程之后重新诊断。2.4 类别变量与目标变量的关系探查4-EDA Medical Cost Personal Dataset.py和9-Exploratory Data Analysis EDA.py中大量使用了matplotlib.pyplot和seaborn做可视化。根据代码逻辑和输出核心是画三类图箱型图展示 smoker 与 charges 的关系小提琴图展示 region 对 charges 的影响以及 pairplot 查看数值特征间的两两分布。import matplotlib.pyplot as plt import seaborn as sns fig, axes plt.subplots(1, 2, figsize(14, 5)) # 吸烟者 vs 非吸烟者的费用分布 sns.boxplot(xsmoker, ycharges, datadf, axaxes[0]) axes[0].set_title(Smoker vs Charges) # 地区与费用的关系 sns.violinplot(xregion, ycharges, datadf, axaxes[1]) axes[1].set_title(Region vs Charges) plt.tight_layout() plt.show()这段可视化的结论在后续建模中直接决定特征策略smoker 字段区分度极高非吸烟者费用主要集中在 5000 以下区间而吸烟者费用中位数在 30000 以上这是模型中最强的单一预测因子。region 的区分度则较弱四个地区间的费用分布高度重叠——这解释了后续脚本中 region 特征权重往往很小的原因。3. 特征工程从原始字段到模型可用输入的完整转换3.1 标签编码与独热编码的选择资源包中3-Predict Medical Cost with SVR R2 88.py和6-Charges Pred w Ridge Regression.py分别使用了不同的编码策略。sex、smoker 是二分类变量用LabelEncoder转为 0/1 即可region 有四个取值需要OneHotEncoder转成多维哑变量否则线性模型会把 region 的类别大小关系错误地当成数值大小关系。from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.compose import make_column_transformer import pandas as pd # 二分类变量用标签编码 le_sex LabelEncoder() le_smoker LabelEncoder() df[sex_encoded] le_sex.fit_transform(df[sex]) df[smoker_encoded] le_smoker.fit_transform(df[smoker]) # 多分类变量用独热编码 df_encoded pd.get_dummies(df, columns[region], prefixregion, drop_firstTrue)代码说明LabelEncoder适合有序或二分类变量将 smoker 的 yes/no 映射为 1/0 后可直接参与数值运算get_dummies是 pandas 提供的独热编码实现drop_firstTrue表示丢弃第一个类别避免哑变量陷阱即完全共线性。这一步做完后原始 7 个字段扩展为 9 个模型可用特征其中region_northwest、region_southeast、region_southwest为哑变量。3.2 数值特征标准化StandardScaler 与 MinMaxScaler 的适用差异16-Experimentation for Insurance Cost R2 87 2.py使用了StandardScaler而20-REGRESI LINEAR.py使用了MinMaxScaler。两者的选择依据是模型类型线性回归、Ridge、Lasso、SVR 这类对特征尺度敏感的模型必须标准化而树模型RandomForest、XGBoost、DecisionTree不需要。资源包中 SVR 脚本取得 R² 0.88 的成绩与正确使用 StandardScaler 有直接关系——SVR 依赖距离计算特征量纲不一致会导致低量纲特征完全失去作用。from sklearn.preprocessing import StandardScaler, MinMaxScaler # 数值特征列表 num_cols [age, bmi, children] # StandardScaler: 零均值单位方差 scaler_std StandardScaler() df_std df.copy() df_std[num_cols] scaler_std.fit_transform(df_std[num_cols]) # MinMaxScaler: 映射到 [0, 1] 区间 scaler_mm MinMaxScaler() df_mm df.copy() df_mm[num_cols] scaler_mm.fit_transform(df_mm[num_cols]) print(StandardScaler 后的 bmi 均值:, df_std[bmi].mean().round(6)) print(MinMaxScaler 后的 bmi 范围:, df_mm[bmi].min(), -, df_mm[bmi].max())参数说明StandardScaler()移除均值并缩放至单位方差适合数据近似正态分布的情形MinMaxScaler()将数据压缩到 [0,1] 区间适合有界数据或需要保持稀疏性的场景。对于存在极端值的 bmi 字段StandardScaler 更稳健因为 MinMaxScaler 会把最大值变成 1导致大部分数据挤压在零附近。3.3 多项式特征与正则化的配合7-LR with Polynomial Features and Regularization.py是最值得细读的脚本之一。核心做法是使用PolynomialFeatures让线性回归获得非线性拟合能力同时用Ridge控制多项式带来的过拟合风险。from sklearn.preprocessing import PolynomialFeatures from sklearn.pipeline import make_pipeline from sklearn.linear_model import Ridge # 生成二阶多项式特征 poly PolynomialFeatures(degree2, include_biasFalse) # 管道封装多项式扩展 → 标准化 → 岭回归 poly_ridge_model make_pipeline( PolynomialFeatures(degree2, include_biasFalse), StandardScaler(), Ridge(alpha1.0) ) # 训练集拟合 poly_ridge_model.fit(X_train, y_train) # 查看生成的特征数量 X_poly poly.fit_transform(X_train) print(原始特征数:, X_train.shape[1]) print(二阶多项式特征数:, X_poly.shape[1])逻辑说明degree2时原始 6 个特征会扩展为 28 个特征6 个一次项 6 个平方项 21 个两两交叉项减 5因为include_biasFalse去掉了常数项。make_pipeline把三步串联成一个整体fit时自动依次执行变换和回归predict时自动做相同变换。Ridge 的alpha1.0是正则化强度值越大对系数压缩越狠。资源包中的实验数据显示多项式Ridge 的组合在测试集上明显优于纯线性回归但也提醒多项式的 degree 不要超过 3否则特征数量爆炸式增长且过拟合风险急剧上升。4. 模型对比与调参从线性回归到 XGBoost 的完整实验4.1 线性回归与正则化模型的参数语义13-insurance cost prediction linear regression.py、6-Charges Pred w Ridge Regression.py和12-Regression with RandomForest.py分别对应线性模型、岭回归和随机森林三类不同复杂度的模型。线性回归无超参数可调但它是判断数据是否符合线性假设的基线Ridge 需要调alphaLasso 同样需要调alpha且自带特征选择能力——12-Regression with RandomForest.py中没有 Lasso 的对比但18-Linear Regression dr ban11.py的 VIF 分析表明特征间共线性不强Lasso 在实际效果上可能与 Ridge 差异不大。下表汇总了资源包中涉及模型的关键参数的含义与推荐搜索范围模型关键参数含义推荐调参范围LinearRegression无最小二乘拟合无需调参RidgealphaL2 正则化强度0.01 ~ 100对数尺度网格LassoalphaL1 正则化强度0.001 ~ 10ElasticNetalpha, l1_ratioL1/L2 混合比例alpha: 0.001~1, l1_ratio: 0.1~0.9SVRC, epsilon, kernel惩罚系数、误差容限、核函数C: 0.1~100, epsilon: 0.01~0.1RandomForestn_estimators, max_depth树数量、最大深度100~500, 5~15XGBoostn_estimators, learning_rate, max_depth树数量、学习率、深度100~300, 0.01~0.1, 3~74.2 GridSearchCV 与交叉验证的具体实现16-Experimentation for Insurance Cost R2 87 2.py中使用了GridSearchCV和KFold。网格搜索与 K 折交叉验证是参数调优的标准组合K 折把训练数据分成 K 份轮流用 K-1 份训练、1 份验证GridSearchCV 在参数网格中遍历所有组合以交叉验证的平均分作为选择依据。以下代码展示了如何在 SVR 上执行网格搜索from sklearn.svm import SVR from sklearn.model_selection import GridSearchCV, KFold from sklearn.preprocessing import StandardScaler from sklearn.pipeline import make_pipeline # 管道标准化 SVR pipe make_pipeline(StandardScaler(), SVR()) # 参数网格 param_grid { svr__C: [0.1, 1, 10], svr__epsilon: [0.01, 0.05, 0.1], svr__kernel: [rbf] } # KFold 5 折交叉验证 kf KFold(n_splits5, shuffleTrue, random_state42) # 网格搜索 grid_search GridSearchCV( estimatorpipe, param_gridparam_grid, cvkf, scoringr2, n_jobs-1, verbose1 ) grid_search.fit(X_train, y_train) print(最优参数:, grid_search.best_params_) print(最优交叉验证 R²:, grid_search.best_score_.round(4)) print(测试集 R²:, grid_search.score(X_test, y_test).round(4))代码逻辑说明param_grid中的键名格式为“组件名__参数名”管道中 SVR 组件名为svr所以写svr__C。cvkf传入自定义的 5 折交叉验证器random_state42固定数据切分顺序保证实验可复现。scoringr2指定以 R² 作为模型评估指标。n_jobs-1让网格搜索并行计算缩短调参时间。最优参数组合会被存储到best_params_中后续可以用grid_search.best_estimator_直接调用最优模型。4.3 树模型的实验对比与 R² 解读12-Regression with RandomForest.py和19-Medical_Analysis_With_LR.py分别使用随机森林与线性回归而15-Medical_Cost_Prediction.py中引入了mutual_info_regression做特征相关性分析。mutual_info_regression可以评估单个特征与目标变量之间的互信息值这个值不依赖线性假设对树模型和线性模型都有参考价值。from sklearn.feature_selection import mutual_info_regression X_features [age, bmi, children, sex_encoded, smoker_encoded, region_northwest, region_southeast, region_southwest] X_mi df_encoded[X_features] y_mi df_encoded[charges] # 计算互信息 mi_scores mutual_info_regression(X_mi, y_mi, random_state42) mi_df pd.DataFrame({feature: X_features, mutual_info: mi_scores}) mi_df mi_df.sort_values(mutual_info, ascendingFalse) print(mi_df)互信息计算结果通常显示smoker_encoded 的互信息值远高于其他特征age 排名第二bmi 第三。这与业务常识高度一致也验证了后续模型中特征权重的合理性。5. 模型自动选择与过拟合识别少走弯路的两个判断技巧将 20 个脚本综合对比后可以总结出两个最重要的工程经验。第一个技巧用训练集与测试集的 R² 差值识别过拟合。在7-LR with Polynomial Features and Regularization.py中如果纯多项式回归在训练集上 R² 达到 0.90但测试集只有 0.75说明 degree 过高或缺少正则化。加入 Ridge 后训练集 R² 可能降到 0.85但测试集提升到 0.83——这是正则化在压缩方差。我一般以“训练集 R² − 测试集 R²”作为过拟合指标差值小于 0.05 为健康。对保险费用预测这个数据集随机森林的差值通常在 0.10 以上说明树模型过拟合倾向明显需要限制max_depth或增大min_samples_leaf。第二个技巧使用遥感变换Box-Cox和标准化后的特征重跑同一模型比较 R² 的增量。资源包中16-Experimentation for Insurance Cost R2 87 2.py的做法是先对 charges 做 Box-Cox 变换再标准化特征最后跑模型R² 达到 0.872。对比13-insurance cost prediction linear regression.py中不对目标变量做变换、直接用原始值训练的结果R² 通常在 0.75 左右。同样一组特征仅仅因为目标变量的分布不同模型表现差距超过 10 个百分点。这说明在回归任务中目标变量的正态化处理往往比换用更复杂的模型更有效。建议先尝试“Box-Cox StandardScaler LinearRegression/Ridge”如果 R² 达不到预期再考虑 SVR 或 XGBoost。对于树模型则不需要做目标变换因为树的 split 判断不依赖数据分布假设。最后一个建议19-Medical_Analysis_With_LR.py中使用的summarytools.dfSummary虽然能快速生成数据摘要但并非 sklearn 的标准模块实际生产中建议直接用 pandas 的df.info()和df.describe(includeall)替代避免因第三方库缺失导致脚本报错。这 20 个脚本的价值在于实验路径的完整性你可以按“先跑通、再对比、后替换”的顺序消化把每个脚本当作一次独立的实验记录来读。本文还有配套的精品资源点击获取
返回列表