问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

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

创作时间:
作者:
@小白创作中心

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

引用
CSDN
1.
https://m.blog.csdn.net/qq_57063846/article/details/145580512

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

数据集简介

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

  • age:被保险人的年龄
  • sex:被保险人的性别(male/female)
  • bmi:体质指数(Body Mass Index)
  • children:子女数量
  • smoker:是否吸烟(yes/no)
  • region:居住地区(northwest, southeast, northeast, southwest)
  • charges:保险费用(目标变量)

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

age
sex
bmi
children
smoker
region
charges
19
female
27.900
0
yes
southwest
16884.92400
18
male
33.770
1
no
southeast
1725.55230
28
male
33.000
3
no
southeast
4449.46200
33
male
22.705
0
no
northwest
21984.47061
32
male
28.880
0
no
northwest
3866.85520

数据探索性分析(EDA)

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

目标变量分布

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

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的分布明显右偏。为了使数据更接近正态分布,我们对其进行对数变换:

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)分析不同特征对保险费用的影响。

性别与保险费用

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()

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

地区与保险费用

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()

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

吸烟状态与保险费用

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分析,我们发现region和sex对保险费用的影响较小,因此可以将其从数据集中移除:

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

二值化处理

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

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被分为“有”和“无”。

独热编码

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

data = pd.get_dummies(data)

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

age
charges
bmi_over
bmi_under
children_no
children_yes
smoker_no
smoker_yes
19
16884.92
False
True
True
False
False
True
18
1725.55
True
False
False
True
True
False

模型训练与评估

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

数据分割与标准化

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)

多项式特征

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

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)

线性回归模型

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

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):

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):

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号