保险费用预测实战:20个Python脚本从线性回归到XGBoost

📅 发布时间:2026/10/1 11:41:35
保险费用预测实战:20个Python脚本从线性回归到XGBoost
简介本资源面向机器学习入门与进阶学习者提供个人健康保险费用预测的完整实战案例帮助读者掌握从数据探索到模型调优的全流程。包内共22个文件以20个Python源代码为主另含1个CSV数据集和1个说明文件压缩包约58KB代码手工整理、无语法错误且可直接运行。案例覆盖数据清洗、探索性分析、统计检验、特征工程与回归建模涉及线性回归、岭回归、Lasso、弹性网络、多项式特征、随机森林、SVR、XGBoost及决策树等多种算法并包含网格搜索、交叉验证、VIF共线性诊断、Box-Cox变换与Bokeh可视化等实用技巧。目前已有77人学习适合希望系统练习回归预测、对比模型效果并积累特征处理经验的读者参考。1. 个人健康保险费用预测一份能直接跑通的 20 脚本实战包保险费用预测是机器学习回归任务里少有的「数据干净、业务清晰、结果可解释」的练手场景。这份资源把同一份insurance.csv1338 行、7 列反复拆解了 20 遍从最朴素的线性回归一路做到 SVR、随机森林、XGBoost还夹带了 EDA、统计检验、Box-Cox 变换和正则化调参。它解决的不是「教你什么是回归」而是「同一份数据在不同模型、不同特征工程下到底差多少」——R² 从 0.75 到 0.88 的差距全藏在脚本编号里。适合已经会写train_test_split、但没系统对比过模型边界的从业者也适合想拿一份完整代码对照自己流程的新手。54.32 KB 的数据集不大但 20 个脚本的覆盖密度比很多付费课都实在。2. 数据底子与脚本地图先搞清楚 1338 行里有什么2.1 insurance.csv 的字段结构与分布陷阱拿到数据第一件事不是建模是确认字段含义和分布形态。insurance.csv共 7 列age18–64 整数、sexmale/female、bmi15.96–53.13 浮点、children0–5 整数、smokeryes/no、regionnortheast/northwest/southeast/southwest、charges1121.87–63770.43 浮点目标变量。常见做法是先跑一遍df.describe()和df.info()但这份资源里4-EDA Medical Cost Personal Dataset.py和9-Exploratory Data Analysis EDA.py做得更细用scipy.stats.skew和kurtosis量化偏度峰度用boxcox试探目标变量正态性。charges的偏度约 1.51峰度约 1.60右偏明显——这直接决定了后面为什么有人用对数变换、有人用 Box-Cox。import pandas as pd import numpy as np from scipy.stats import skew, kurtosis df pd.read_csv(insurance.csv) print(df.shape) # (1338, 7) print(df.isnull().sum()) # 全 0无缺失 print(df[charges].describe()) print(skew:, skew(df[charges])) # ~1.51 print(kurtosis:, kurtosis(df[charges])) # ~1.60 # 分类变量取值分布 for col in [sex, smoker, region]: print(col, df[col].value_counts().to_dict())逻辑说明先确认无缺失再谈建模避免后面插补逻辑干扰对比。参数上skew和kurtosis默认对样本计算kurtosis返回的是超额峰度正态为 0所以 1.60 意味着比正态尖。这一步的产出是「要不要对 charges 做变换」的判断依据不是走形式。2.2 20 个脚本的编号逻辑与选型路线脚本编号不是随便排的大致分四条线编号段主题代表脚本1–5基础预测与初步分析1-Predicting Medical Insurance Costs.py、2-Medical Cost Analysis.py6–8正则化与多项式特征6-Charges Pred w Ridge Regression.py、7-LR with Polynomial Features and Regularization.py9–14EDA 与统计检验9-Exploratory Data Analysis EDA.py、11-Statistical Analysis of Medical Cost Datasets.py15–20多模型对比与调参12-Regression with RandomForest.py、3-Predict Medical Cost with SVR R2 88.py、16-Experimentation for Insurance Cost R2 87 2.py3-Predict Medical Cost with SVR R2 88.py和16-Experimentation for Insurance Cost R2 87 2.py文件名直接标了 R²说明作者在整理时已经跑出过结果。13-insurance cost prediction linear regression.py和20-REGRESI LINEAR.py是同一算法的不同写法适合对照看特征处理差异。提示不要按编号顺序全跑一遍先跑 1、3、12、16 四个建立基线认知再回头补 EDA 和统计脚本。3. 从线性回归到随机森林四类模型的落地步骤3.1 线性回归基线OneHot 标准化 交叉验证1-Predicting Medical Insurance Costs.py和13-insurance cost prediction linear regression.py走的是最标准的流程。关键点在于分类变量处理sex、smoker、region用OneHotEncoder或LabelEncoder数值变量age、bmi、children用StandardScaler。资源里sklearn.compose.make_column_transformer出现在模块列表中说明有脚本用了列变换器统一处理。from sklearn.compose import make_column_transformer from sklearn.preprocessing import OneHotEncoder, StandardScaler from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split, cross_val_score from sklearn.pipeline import make_pipeline from sklearn.metrics import r2_score, mean_absolute_error X df.drop(charges, axis1) y df[charges] preprocess make_column_transformer( (StandardScaler(), [age, bmi, children]), (OneHotEncoder(dropfirst), [sex, smoker, region]) ) pipe make_pipeline(preprocess, LinearRegression()) X_train, X_test, y_train, y_test train_test_split(X, y, test_size0.2, random_state42) pipe.fit(X_train, y_train) pred pipe.predict(X_test) print(R2:, r2_score(y_test, pred)) # 约 0.78 print(MAE:, mean_absolute_error(y_test, pred)) print(CV R2:, cross_val_score(pipe, X, y, cv5, scoringr2).mean())逻辑说明make_column_transformer把数值标准化和类别独热编码串在一起避免手动fit_transform顺序出错。OneHotEncoder(dropfirst)去掉一列防共线性对线性回归是必要操作。cross_val_score用 5 折交叉验证比单次train_test_split更稳。参数上test_size0.2、random_state42是资源里反复出现的组合方便复现。线性回归的 R² 大约 0.75–0.78瓶颈在于smoker和bmi的交互效应没被捕捉——吸烟且高 BMI 的人群费用是非线性飙升的线性模型只能给一个固定系数。3.2 多项式特征与正则化Ridge、Lasso、ElasticNet 怎么选7-LR with Polynomial Features and Regularization.py和6-Charges Pred w Ridge Regression.py解决的就是上面那个瓶颈。做法是用PolynomialFeatures(degree2)生成交互项和平方项再用 Ridge/Lasso/ElasticNet 控制过拟合。from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import Ridge, Lasso, ElasticNet from sklearn.model_selection import GridSearchCV poly_pipe make_pipeline( preprocess, PolynomialFeatures(degree2, include_biasFalse), Ridge() ) param_grid {ridge__alpha: [0.01, 0.1, 1, 10, 100]} grid GridSearchCV(poly_pipe, param_grid, cv5, scoringr2) grid.fit(X_train, y_train) print(best alpha:, grid.best_params_) print(best R2:, grid.best_score_)逻辑说明PolynomialFeatures(degree2)会把 6 个原始特征扩展到约 27 个含交互项include_biasFalse因为后面有截距。Ridge 的alpha控制 L2 惩罚强度GridSearchCV在 5 折上搜。资源里同时有 Lasso 和 ElasticNet区别是 Lasso 做 L1 能稀疏化特征、ElasticNet 混合 L1/L2。常见做法是 degree 不超过 2再高会爆维度且 R² 提升有限。这一路 R² 能到 0.83–0.85比纯线性高 5–7 个百分点。坑在于多项式特征对age、bmi的尺度敏感必须先标准化再进PolynomialFeatures否则高次项数值爆炸。3.3 SVR 与随机森林非线性模型的参数边界3-Predict Medical Cost with SVR R2 88.py和12-Regression with RandomForest.py是两个非线性代表。SVR 用 RBF 核关键参数是C、gamma、epsilon随机森林用n_estimators、max_depth、min_samples_split。from sklearn.svm import SVR from sklearn.ensemble import RandomForestRegressor svr_pipe make_pipeline(preprocess, SVR(kernelrbf, C100, gamma0.1, epsilon0.1)) svr_pipe.fit(X_train, y_train) print(SVR R2:, r2_score(y_test, svr_pipe.predict(X_test))) # 约 0.86-0.88 rf_pipe make_pipeline(preprocess, RandomForestRegressor( n_estimators200, max_depth10, min_samples_split5, random_state42)) rf_pipe.fit(X_train, y_train) print(RF R2:, r2_score(y_test, rf_pipe.predict(X_test))) # 约 0.85-0.87逻辑说明SVR 对特征尺度极敏感preprocess里的StandardScaler不能省。C100是资源里调出来的较大值说明数据非线性强、需要较松的间隔。随机森林不需要标准化但max_depth10是防过拟合的关键——不限制深度时训练集 R² 能到 0.98测试集反而掉。n_estimators200是精度和耗时的平衡点再往上收益递减。注意SVR 在 1338 行数据上训练很快但换成几万行就会明显变慢随机森林的扩展性更好。3.4 XGBoost 与特征重要性最后 1–2 个点的来源模块列表里有xgboost.XGBRegressor对应16-Experimentation for Insurance Cost R2 87 2.py这类脚本。XGBoost 在表格数据上通常比随机森林再高一点且能直接输出特征重要性。from xgboost import XGBRegressor xgb_pipe make_pipeline(preprocess, XGBRegressor( n_estimators300, learning_rate0.05, max_depth4, subsample0.8, colsample_bytree0.8, random_state42)) xgb_pipe.fit(X_train, y_train) print(XGB R2:, r2_score(y_test, xgb_pipe.predict(X_test))) # 约 0.87-0.88 # 特征重要性需取出编码后特征名 model xgb_pipe.named_steps[xgbregressor] print(model.feature_importances_)逻辑说明learning_rate0.05配n_estimators300是慢学习率多轮次的经典组合max_depth4控制单棵树复杂度subsample和colsample_bytree做行/列采样防过拟合。特征重要性通常显示smoker和bmi排前二age第三和业务直觉一致。这一步的产出不只是 R²还有「哪些特征真正在驱动费用」的可解释结论。4. 避坑与排查跑这 20 个脚本时最容易翻车的五处4.1 现象OneHotEncoder 报错「unknown category」原因训练集和测试集分别fit编码器测试集出现训练集没见过的类别。解决用make_column_transformer或ColumnTransformer在管道里统一fit或者OneHotEncoder(handle_unknownignore)。资源里多个脚本用管道就是为了避开这个。4.2 现象多项式特征后 R² 反而下降原因PolynomialFeatures放在StandardScaler之前高次项数值溢出或者 degree 设成 3 以上维度爆炸。解决确保管道顺序是「标准化 → 多项式 → 模型」degree 控制在 2。7-LR with Polynomial Features and Regularization.py的顺序可以直接抄。4.3 现象SVR 训练极慢或 R² 只有 0.5原因忘了标准化或者gamma设成默认scale但数据尺度差异大。解决SVR 前必须StandardScalergamma从 0.01、0.1、1 手动试C从 1 到 1000 搜。资源里C100是调过的结果不是默认值。4.4 现象随机森林训练集 R² 0.98、测试集 0.80原因树太深、叶子节点样本太少模型把训练集噪声也学了。解决限制max_depth8–12、提高min_samples_split5–10、加min_samples_leaf。12-Regression with RandomForest.py里有现成参数组合。4.5 现象summarytools.dfSummary或bokeh导入失败原因这两个不是 sklearn 生态的必装包资源里部分脚本用了但环境不一定有。解决pip install summarytools bokeh或者直接跳过这两个脚本核心建模脚本不依赖它们。14-notebook00e6761e59.py这种带哈希名的文件可能是导出残留优先跑编号清晰的。5. 把 R² 从 0.88 再往上推特征工程与验证的进阶手法到 0.88 之后单纯换模型收益很小了真正能再挤出 1–2 个点的是特征交互和验证策略。资源里11-Statistical Analysis of Medical Cost Datasets.py用了variance_inflation_factor查共线性scipy.stats.boxcox试探目标变换这两步是进阶的入口。第一个手法是手动构造smoker_bmi交互项。业务上吸烟和高 BMI 的叠加效应远大于两者单独之和线性模型和树模型都不一定能自动捕捉到这种乘法关系。做法很简单df[smoker_bmi] df[smoker].map({yes: 1, no: 0}) * df[bmi] df[age_smoker] df[age] * df[smoker].map({yes: 1, no: 0})加完这两个特征再跑随机森林或 XGBoostR² 通常能到 0.89–0.90。注意这两个特征和原始smoker、bmi有共线性线性模型里要谨慎树模型无所谓。第二个手法是对charges做 Box-Cox 或对数变换后再建模预测时再逆变换回来。charges右偏严重变换后残差更接近正态线性模型的 R² 能提升明显。但树模型对单调变换不敏感所以这条主要针对线性族。第三个手法是换验证策略。资源里多数脚本用train_test_split或cross_val_score但KFold出现在模块列表里说明有脚本做了更细的折划分。对 1338 行的小数据建议用KFold(n_splits10, shuffleTrue, random_state42)替代默认 5 折R² 的方差会小很多调参结果更可信。from sklearn.model_selection import KFold, cross_val_score kf KFold(n_splits10, shuffleTrue, random_state42) scores cross_val_score(xgb_pipe, X, y, cvkf, scoringr2) print(10-fold R2: %.4f (/- %.4f) % (scores.mean(), scores.std()))逻辑说明shuffleTrue必须加否则数据按原始顺序切分可能引入分布偏差。scores.std()反映模型稳定性标准差大于 0.03 说明调参过拟合了某几折。最后一个习惯每次改特征或参数固定random_state只改一个变量记录 R² 和 MAE 两个指标。我早期图省事一次改三四个地方结果 R² 涨了也不知道是谁的功劳跌了更不知道回退哪一步。从那以后我每次做回归对比都强制走一遍「单变量改动 双指标记录」这份资源的 20 个脚本正好可以当对照模板用。希望帮到你。本文还有配套的精品资源点击获取