实战保险花销预测进阶:从数据探索到模型优化

实战保险花销预测:从数据探索到模型优化

在数据分析和机器学习领域,预测保险花销是一个经典的回归问题。本文将详细介绍如何通过 Python 和机器学习算法,从数据探索到模型优化,逐步实现保险花销的预测。我们将使用一个公开的保险数据集,通过特征工程、模型选择和评估,最终构建一个准确的预测模型。

数据集简介

本次使用的保险数据集包含以下字段:

  • age:被保险人的年龄

  • sex:被保险人的性别(male/female)

  • bmi:体质指数(Body Mass Index)

  • children:子女数量

  • smoker:是否吸烟(yes/no)

  • region:居住地区(northwest, southeast, northeast, southwest)

  • charges:保险花销(目标变量)

以下是数据集的前几行示例:

agesexbmichildrensmokerregioncharges
19female27.9000yessouthwest16884.92400
18male33.7701nosoutheast1725.55230
28male33.0003nosoutheast4449.46200
33male22.7050nonorthwest21984.47061
32male28.8800nonorthwest3866.85520

数据探索性分析(EDA)

在进行模型训练之前,我们需要对数据进行初步探索,了解各特征与目标变量之间的关系。

目标变量分布

首先,我们绘制 charges 的直方图,观察其分布情况:

Python复制

import matplotlib.pyplot as plt

plt.hist(data['charges'], bins=20)
plt.title('Distribution of Charges')
plt.xlabel('Charges')
plt.ylabel('Frequency')
plt.show()

从图中可以看出,charges 的分布明显右偏。为了使数据更接近正态分布,我们对其进行对数变换:

Python复制

plt.hist(np.log(data['charges']), bins=20)
plt.title('Log-transformed Distribution of Charges')
plt.xlabel('Log(Charges)')
plt.ylabel('Frequency')
plt.show()

对数变换后的数据分布更加均匀,这有助于后续的回归分析。

特征与目标变量的关系

接下来,我们通过核密度图(KDE)分析不同特征对保险花销的影响。

性别与保险花销

Python复制

import seaborn as sns

sns.kdeplot(data.loc[data.sex == 'male', 'charges'], fill=True, label='male')
sns.kdeplot(data.loc[data.sex == 'female', 'charges'], fill=True, label='female')
plt.legend()
plt.title('Charges by Gender')
plt.xlabel('Charges')
plt.ylabel('Density')
plt.show()

从图中可以看出,男性和女性的保险花销分布差异不大。

地区与保险花销

Python复制

sns.kdeplot(data.loc[data.region == 'northwest', 'charges'], fill=True, label='northwest')
sns.kdeplot(data.loc[data.region == 'southwest', 'charges'], fill=True, label='southwest')
sns.kdeplot(data.loc[data.region == 'northeast', 'charges'], fill=True, label='northeast')
sns.kdeplot(data.loc[data.region == 'southeast', 'charges'], fill=True, label='southeast')
plt.legend()
plt.title('Charges by Region')
plt.xlabel('Charges')
plt.ylabel('Density')
plt.show()

不同地区的保险花销分布也较为接近,说明地区对保险花销的影响较小。

吸烟状态与保险花销

Python复制

sns.kdeplot(data.loc[data.smoker == 'yes', 'charges'], fill=True, label='smoker yes')
sns.kdeplot(data.loc[data.smoker == 'no', 'charges'], fill=True, label='smoker no')
plt.legend()
plt.title('Charges by Smoking Status')
plt.xlabel('Charges')
plt.ylabel('Density')
plt.show()

从图中可以看出,吸烟者的保险花销明显高于非吸烟者,这表明吸烟状态是一个重要的影响因素。

特征工程

在机器学习中,特征工程是提高模型性能的关键步骤。我们将对数据进行清理和转换,以提取更有用的特征。

去除不重要特征

通过 EDA 分析,我们发现 regionsex 对保险花销的影响较小,因此可以将其从数据集中移除:

Python复制

data = data.drop(['region', 'sex'], axis=1)

二值化处理

我们将 bmichildren 进行二值化处理,以简化模型:

Python复制

def greater(df, bmi, num_child):
    df['bmi'] = 'over' if df['bmi'] >= bmi else 'under'
    df['children'] = 'no' if df['children'] == num_child else 'yes'
    return df

data = data.apply(greater, axis=1, args=(30, 0))

这样,bmi 被分为“超过 30”和“不超过 30”,children 被分为“有”和“无”。

独热编码

由于 bmichildren 是分类变量,我们需要对其进行独热编码(One-Hot Encoding):

Python复制

data = pd.get_dummies(data)

独热编码后的数据如下所示:

agechargesbmi_overbmi_underchildren_nochildren_yessmoker_nosmoker_yes
1916884.92FalseTrueTrueFalseFalseTrue
181725.55TrueFalseFalseTrueTrueFalse

模型训练与评估

在完成特征工程后,我们将数据分为训练集和测试集,并对模型进行训练和评估。

数据分割与标准化

Python复制

from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

x = data.drop('charges', axis=1)
y = data['charges']

x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)

scaler = StandardScaler().fit(x_train)
x_train_scaled = scaler.transform(x_train)
x_test_scaled = scaler.transform(x_test)

多项式特征

为了捕捉特征之间的非线性关系,我们对特征进行多项式升维:

Python复制

from sklearn.preprocessing import PolynomialFeatures

poly_features = PolynomialFeatures(degree=2, include_bias=False)
x_train_scaled = poly_features.fit_transform(x_train_scaled)
x_test_scaled = poly_features.transform(x_test_scaled)

线性回归模型

我们首先使用线性回归模型进行训练:

Python复制

from sklearn.linear_model import LinearRegression
from sklearn.metrics import mean_squared_error

reg = LinearRegression()
reg.fit(x_train_scaled, np.log1p(y_train))

y_predict_linear = reg.predict(x_test_scaled)

log_rmse_train = np.sqrt(mean_squared_error(np.log1p(y_train), reg.predict(x_train_scaled)))
log_rmse_test = np.sqrt(mean_squared_error(np.log1p(y_test), y_predict_linear))
rmse_train = np.sqrt(mean_squared_error(y_train, np.exp(reg.predict(x_train_scaled))))
rmse_test = np.sqrt(mean_squared_error(y_test, np.exp(y_predict_linear)))

print(f"Log RMSE (Train): {log_rmse_train}")
print(f"Log RMSE (Test): {log_rmse_test}")
print(f"RMSE (Train): {rmse_train}")
print(f"RMSE (Test): {rmse_test}")

评估结果如下:

  • Log RMSE (Train): 0.3604

  • Log RMSE (Test): 0.4246

  • RMSE (Train): 4285.55

  • RMSE (Test): 5374.22

岭回归模型

为了防止过拟合,我们尝试使用岭回归(Ridge Regression):

Python复制

from sklearn.linear_model import Ridge

ridge = Ridge(alpha=0.4)
ridge.fit(x_train_scaled, np.log1p(y_train))

y_predict_ridge = ridge.predict(x_test_scaled)

log_rmse_train = np.sqrt(mean_squared_error(np.log1p(y_train), ridge.predict(x_train_scaled)))
log_rmse_test = np.sqrt(mean_squared_error(np.log1p(y_test), y_predict_ridge))
rmse_train = np.sqrt(mean_squared_error(y_train, np.exp(ridge.predict(x_train_scaled))))
rmse_test = np.sqrt(mean_squared_error(y_test, np.exp(y_predict_ridge)))

print(f"Log RMSE (Train): {log_rmse_train}")
print(f"Log RMSE (Test): {log_rmse_test}")
print(f"RMSE (Train): {rmse_train}")
print(f"RMSE (Test): {rmse_test}")

评估结果如下:

  • Log RMSE (Train): 0.3604

  • Log RMSE (Test): 0.4245

  • RMSE (Train): 4285.56

  • RMSE (Test): 5374.61

梯度提升回归模型

最后,我们尝试使用梯度提升回归(Gradient Boosting Regressor):

Python复制

from sklearn.ensemble import GradientBoostingRegressor

booster = GradientBoostingRegressor()
booster.fit(x_train_scaled, np.log1p(y_train))

y_predict_boost = booster.predict(x_test_scaled)

log_rmse_train = np.sqrt(mean_squared_error(np.log1p(y_train), booster.predict(x_train_scaled)))
log_rmse_test = np.sqrt(mean_squared_error(np.log1p(y_test), y_predict_boost))
rmse_train = np.sqrt(mean_squared_error(y_train, np.exp(booster.predict(x_train_scaled))))
rmse_test = np.sqrt(mean_squared_error(y_test, np.exp(y_predict_boost)))

print(f"Log RMSE (Train): {log_rmse_train}")
print(f"Log RMSE (Test): {log_rmse_test}")
print(f"RMSE (Train): {rmse_train}")
print(f"RMSE (Test): {rmse_test}")

评估结果如下:

  • Log RMSE (Train): 0.3428

  • Log RMSE (Test): 0.4245

  • RMSE (Train): 3942.97

  • RMSE (Test): 5244.94

结论

通过对比线性回归、岭回归和梯度提升回归的评估结果,我们发现:

  • 梯度提升回归在训练集上的表现略优于其他模型,但测试集上的表现与线性回归和岭回归相近。

  • 误差仍在 5000 左右,说明模型仍有改进空间。我们可以尝试更复杂的特征工程或选择更先进的算法来进一步提高预测精度。

在实际应用中,模型的选择和优化需要根据具体问题和数据进行调整。通过本文的介绍,相信你已经对如何进行保险花销预测有了更深入的了解。

源码地址:https://gitee.com/jinwaifei/artificial-intelligence-project/tree/master/%E5%AE%9E%E6%88%98%E4%BF%9D%E9%99%A9%E8%8A%B1%E9%94%80%E9%A2%84%E6%B5%8B

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值