京公网安备 11010802034615号
经营许可证编号:京B2-20210330
CDA数据分析师 出品
作者:真达、Mika
数据:真达
【导读】今天的内容是一期python实战训练,我们来手把手教你用Python分析保险产品交叉销售和哪些因素有关。
01、实战背景
首先介绍下实战的背景, 这次的数据集来自kaggle:
https://www.kaggle.com/anmolkumar/health-insurance-cross-sell-prediction
我们的客户是一家保险公司,最近新推出了一款汽车保险。现在他们的需要是建立一个模型,用来预测去年的投保人是否会对这款汽车保险感兴趣。
我们知道,保险单指的是,保险公司承诺为特定类型的损失、损害、疾病或死亡提供赔偿保证,客户则需要定期向保险公司支付一定的保险费。这里再进一步说明一下。
例如,你每年要为20万的健康保险支付2000元的保险费。那么你肯定会想,保险公司只收取5000元的保费,这种情况下,怎么能承担如此高的住院费用呢? 这时,“概率”的概念就出现了。例如,像你一样,可能有100名客户每年支付2000元的保费,但当年住院的可能只有少数人,(比如2-3人),而不是所有人。通过这种方式,每个人都分担了其他人的风险。
和医疗保险一样,买了车险的话,每年都需要向保险公司支付一定数额的保险费,这样在车辆发生意外事故时,保险公司将向客户提供赔偿(称为“保险金额”)。
我们要做的就是建立模型,来预测客户是否对汽车保险感兴趣。这对保险公司来说是非常有帮助的,公司可以据此制定沟通策略,接触这些客户,并优化其商业模式和收入。
02、数据理解
为了预测客户是否对车辆保险感兴趣,我们需要了解一些客户信息 (性别、年龄等)、车辆(车龄、损坏情况)、保单(保费、采购渠道)等信息。
数据划分为训练集和测试集,训练数据包含381109笔客户资料,每笔客户资料包含12个字段,1个客户ID字段、10个输入字段及1个目标字段-Response是否响应(1代表感兴趣,0代表不感兴趣)。测试数据包含127037笔客户资料;字段个数与训练数据相同,目标字段没有值。字段的定义可参考下文。
下面我们开始吧!
03、数据读入和预览
首先开始数据读入和预览。
# 数据整理 import numpy as np import pandas as pd # 可视化 import matplotlib.pyplot as plt import seaborn as sns import plotly as py import plotly.graph_objs as go import plotly.express as px pyplot = py.offline.plot from exploratory_data_analysis import EDAnalysis # 自定义
# 读入训练集
train = pd.read_csv('../data/train.csv')
train.head()
# 读入测试集
test = pd.read_csv('../data/test.csv')
test.head()
print(train.info())
print('-' * 50)
print(test.info())
<class 'pandas.core.frame.DataFrame'> RangeIndex: 381109 entries, 0 to 381108 Data columns (total 12 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 id 381109 non-null int64 1 Gender 381109 non-null object 2 Age 381109 non-null int64 3 Driving_License 381109 non-null int64 4 Region_Code 381109 non-null float64 5 Previously_Insured 381109 non-null int64 6 Vehicle_Age 381109 non-null object 7 Vehicle_Damage 381109 non-null object 8 Annual_Premium 381109 non-null float64 9 Policy_Sales_Channel 381109 non-null float64 10 Vintage 381109 non-null int64 11 Response 381109 non-null int64 dtypes: float64(3), int64(6), object(3) memory usage: 34.9+ MB None -------------------------------------------------- <class 'pandas.core.frame.DataFrame'> RangeIndex: 127037 entries, 0 to 127036 Data columns (total 11 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 id 127037 non-null int64 1 Gender 127037 non-null object 2 Age 127037 non-null int64 3 Driving_License 127037 non-null int64 4 Region_Code 127037 non-null float64 5 Previously_Insured 127037 non-null int64 6 Vehicle_Age 127037 non-null object 7 Vehicle_Damage 127037 non-null object 8 Annual_Premium 127037 non-null float64 9 Policy_Sales_Channel 127037 non-null float64 10 Vintage 127037 non-null int64 dtypes: float64(3), int64(5), object(3) memory usage: 10.7+ MB None
04、探索性分析
下面,我们基于训练数据集进行探索性数据分析。
1. 描述性分析
首先对数据集中数值型属性进行描述性统计分析。
desc_table = train.drop(['id', 'Vehicle_Age'], axis=1).describe().T desc_table
通过描述性分析后,可以得到以下结论。从以上描述性分析结果可以得出:
2. 目标变量的分布
训练集共有381109笔客户资料,其中感兴趣的有46710人,占比12.3%,不感兴趣的有334399人,占比87.7%。
train['Response'].value_counts() 0 334399 1 46710 Name: Response, dtype: int64
values = train['Response'].value_counts().values.tolist()
# 轨迹
trace1 = go.Pie(labels=['Not interested', 'Interested'],
values=values,
hole=.5,
marker={'line': {'color': 'white', 'width': 1.3}}
)
# 轨迹列表
data = [trace1]
# 布局
layout = go.Layout(title=f'Distribution_ratio of Response', height=600)
# 画布
fig = go.Figure(data=data, layout=layout)
# 生成HTML
pyplot(fig, filename='./html/目标变量分布.html')
3. 性别因素
从条形图可以看出,男性的客户群体对汽车保险感兴趣的概率稍高,是13.84%,相较女性客户高出3个百分点。
pd.crosstab(train['Gender'], train['Response'])
# 实例类 eda = EDAnalysis(data=train, id_col='id', target='Response') # 柱形图 fig = eda.draw_bar_stack_cat(colname='Gender') pyplot(fig, filename='./html/性别与是否感兴趣.html')
4. 之前是否投保
没有购买汽车保险的客户响应概率更高,为22.54%,有购买汽车保险的客户则没有这一需求,感兴趣的概率仅为0.09%。
pd.crosstab(train['Previously_Insured'], train['Response'])
fig = eda.draw_bar_stack_cat(colname='Previously_Insured') pyplot(fig, filename='./html/之前是否投保与是否感兴趣.html')
5. 车龄因素
车龄越大,响应概率越高,大于两年的车龄感兴趣的概率最高,为29.37%,其次是1~2年车龄,概率为17.38%。小于1年的仅为4.37%。
6. 车辆损坏情况
车辆曾经损坏过的客户有较高的响应概率,为23.76%,相比之下,客户过去车辆没有损坏的响应概率仅为0.52%
7. 不同年龄
从直方图中可以看出,年龄较高的群体和较低的群体响应的概率较低,30~60岁之前的客户响应概率较高。通过可视化探索,我们大致可以知道:
车龄在1年以上,之前有车辆损坏的情况出现,且未购买过车辆保险的客户有较高的响应概率。
05、数据预处理
此部分工作主要包含字段选择,数据清洗和数据编码,字段的处理如下:
# 删除字段 train = train.drop(['Region_Code', 'Policy_Sales_Channel'], axis=1) # 盖帽法处理异常值 f_max = train['Annual_Premium'].mean() + 3*train['Annual_Premium'].std() f_min = train['Annual_Premium'].mean() - 3*train['Annual_Premium'].std() train.loc[train['Annual_Premium'] > f_max, 'Annual_Premium'] = f_max train.loc[train['Annual_Premium'] < f_min, 'Annual_Premium'] = f_min # 数据编码 train['Gender'] = train['Gender'].map({'Male': 1, 'Female': 0}) train['Vehicle_Damage'] = train['Vehicle_Damage'].map({'Yes': 1, 'No': 0}) train['Vehicle_Age'] = train['Vehicle_Age'].map({'< 1 Year': 0, '1-2 Year': 1, '> 2 Years': 2}) train.head()
测试集做相同的处理:
# 删除字段 test = test.drop(['Region_Code', 'Policy_Sales_Channel'], axis=1) # 盖帽法处理 test.loc[test['Annual_Premium'] > f_max, 'Annual_Premium'] = f_max test.loc[test['Annual_Premium'] < f_min, 'Annual_Premium'] = f_min # 数据编码 test['Gender'] = test['Gender'].map({'Male': 1, 'Female': 0}) test['Vehicle_Damage'] = test['Vehicle_Damage'].map({'Yes': 1, 'No': 0}) test['Vehicle_Age'] = test['Vehicle_Age'].map({'< 1 Year': 0, '1-2 Year': 1, '> 2 Years': 2}) test.head()
06、数据建模
我们选择使用以下几种模型进行建置,并比较模型的分类效能。首先在将训练集划分为训练集和验证集,其中训练集用于训练模型,验证集用于验证模型效果。首先导入建模库:
# 建模 from sklearn.linear_model import LogisticRegression from sklearn.neighbors import KNeighborsClassifier from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from lightgbm import LGBMClassifier # 预处理 from sklearn.preprocessing import StandardScaler, MinMaxScaler # 模型评估 from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import confusion_matrix, classification_report, accuracy_score, f1_score, roc_auc_score
# 划分特征和标签 X = train.drop(['id', 'Response'], axis=1) y = train['Response'] # 划分训练集和验证集(分层抽样) X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=0.2, stratify=y, random_state=0) print(X_train.shape, X_val.shape, y_train.shape, y_val.shape) (304887, 8) (76222, 8) (304887,) (76222,)
# 处理样本不平衡,对0类样本进行降采样
from imblearn.under_sampling import RandomUnderSampler
under_model = RandomUnderSampler(sampling_strategy={0:133759, 1:37368}, random_state=0)
X_train, y_train = under_model.fit_sample(X_train, y_train)
# 保存一份极值标准化的数据
mms = MinMaxScaler()
X_train_scaled = pd.DataFrame(mms.fit_transform(X_train), columns=x_under.columns)
X_val_scaled = pd.DataFrame(mms.transform(X_val), columns=x_under.columns)
# 测试集
X_test = test.drop('id', axis=1)
X_test_scaled = pd.DataFrame(mms.transform(X_test), columns=X_test.columns)
1. KNN算法
# 建立knn
knn = KNeighborsClassifier(n_neighbors=3, n_jobs=-1)
knn.fit(X_train_scaled, y_train)
y_pred = knn.predict(X_val_scaled)
print('Simple KNeighborsClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred)))
print('Simple KNeighborsClassifier f1_score: %.3f' % (f1_score(y_val, y_pred)))
print('Simple KNeighborsClassifier roc_auc_score: %.3f' % (roc_auc_score(y_val, y_pred)))
Simple KNeighborsClassifier accuracy:0.807 Simple KNeighborsClassifier f1_score: 0.337 Simple KNeighborsClassifier roc_auc_score: 0.632
# 对测试集评估 test_y = knn.predict(X_test_scaled) test_y[:5] array([0, 0, 1, 0, 0], dtype=int64)
2. Logistic回归
# Logistic回归
lr = LogisticRegression()
lr.fit(X_train_scaled, y_train)
y_pred = lr.predict(X_val_scaled)
print('Simple LogisticRegression accuracy:%.3f' % (accuracy_score(y_val, y_pred)))
print('Simple LogisticRegression f1_score: %.3f' % (f1_score(y_val, y_pred)))
print('Simple LogisticRegression roc_auc_score: %.3f' % (roc_auc_score(y_val, y_pred)))
Simple LogisticRegression accuracy:0.863 Simple LogisticRegression f1_score: 0.156 Simple LogisticRegression roc_auc_score: 0.536
3. 决策树
# 决策树 dtc = DecisionTreeClassifier(max_depth=10, random_state=0) dtc.fit(X_train, y_train) y_pred = dtc.predict(X_val) print('Simple DecisionTreeClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred))) print('Simple DecisionTreeClassifier f1_score: %.3f' % (f1_score(y_val, y_pred))) print('Simple DecisionTreeClassifier roc_auc_score: %.3f' % (roc_auc_score(y_val, y_pred)))
Simple DecisionTreeClassifier accuracy:0.849 Simple DecisionTreeClassifier f1_score: 0.310 Simple DecisionTreeClassifier roc_auc_score: 0.603
4. 随机森林
# 决策树 rfc = RandomForestClassifier(n_estimators=100, max_depth=10, n_jobs=-1) rfc.fit(X_train, y_train) y_pred = rfc.predict(X_val) print('Simple RandomForestClassifier accuracy:%.3f' % (accuracy_score(y_val, y_pred))) print('Simple RandomForestClassifier f1_score: %.3f' % (f1_score(y_val, y_pred))) print('Simple RandomForestClassifier roc_auc_score: %.3f' % (roc_auc_score(y_val, y_pred)))
Simple RandomForestClassifier accuracy:0.870 Simple RandomForestClassifier f1_score: 0.177 Simple RandomForestClassifier roc_auc_score: 0.545
5. LightGBM
lgbm = LGBMClassifier(n_estimators=100, random_state=0)
lgbm.fit(X_train, y_train)
y_pred = lgbm.predict(X_val)
print('Simple LGBM accuracy: %.3f' % (accuracy_score(y_val, y_pred)))
print('Simple LGBM f1_score: %.3f' % (f1_score(y_val, y_pred)))
print('Simple LGBM roc_auc_score: %.3f' % (roc_auc_score(y_val, y_pred)))
Simple LGBM accuracy: 0.857 Simple LGBM f1_score: 0.290 Simple LGBM roc_auc_score: 0.591
综上,以f1-score作为评价标准的情况下,KNN算法有较好的分类效能,这可能是由于数据样本本身不平衡导致,后续可以通过其他类别不平衡的方式做进一步处理,同时可以通过参数调整的方式来优化其他模型,通过调整预测的门槛值来增加预测效能等其他方式。
——热门课程推荐:
想学习PYTHON数据分析与金融数字化转型精英训练营,您可以点击>>>“人才转型”了解课程详情;
想从事业务型数据分析师,您可以点击>>>“数据分析师”了解课程详情;
想从事大数据分析师,您可以点击>>>“大数据就业”了解课程详情;
想成为人工智能工程师,您可以点击>>>“人工智能就业”了解课程详情;
想了解Python数据分析,您可以点击>>>“Python数据分析师”了解课程详情;
想咨询互联网运营,你可以点击>>>“互联网运营就业班”了解课程详情;
数据分析咨询请扫描二维码
若不方便扫码,搜微信号:CDAshujufenxi
在信贷业务中,违约率是衡量信贷资产质量、把控信用风险、制定风控策略的核心指标,其统计分布特征直接决定了风险定价的合理性、 ...
2026-02-03在数字化业务迭代中,AB测试已成为验证产品优化、策略调整、运营活动效果的核心工具。但多数业务场景中,单纯的“AB组差异对比” ...
2026-02-03企业战略决策的科学性,决定了其长远发展的格局与竞争力。战略分析方法作为一套系统化、专业化的思维工具,为企业研判行业趋势、 ...
2026-02-03在统计调查与数据分析中,抽样方法分为简单随机抽样与复杂抽样两大类。简单随机抽样因样本均匀、计算简便,是基础的抽样方式,但 ...
2026-02-02在数据驱动企业发展的今天,“数据分析”已成为企业经营决策的核心支撑,但实践中,战略数据分析与业务数据分析两个概念常被混淆 ...
2026-02-02在数据驱动企业发展的今天,“数据分析”已成为企业经营决策的核心支撑,但实践中,战略数据分析与业务数据分析两个概念常被混淆 ...
2026-02-02B+树作为数据库索引的核心数据结构,其高效的查询、插入、删除性能,离不开节点间指针的合理设计。在日常学习和数据库开发中,很 ...
2026-01-30在数据库开发中,UUID(通用唯一识别码)是生成唯一主键、唯一标识的常用方式,其标准格式包含4个短横线(如550e8400-e29b-41d4- ...
2026-01-30商业数据分析的价值落地,离不开标准化、系统化的总体流程作为支撑;而CDA(Certified Data Analyst)数据分析师,作为经过系统 ...
2026-01-30在数据分析、质量控制、科研实验等场景中,数据波动性(离散程度)的精准衡量是判断数据可靠性、稳定性的核心环节。标准差(Stan ...
2026-01-29在数据分析、质量检测、科研实验等领域,判断数据间是否存在本质差异是核心需求,而t检验、F检验是实现这一目标的经典统计方法。 ...
2026-01-29统计制图(数据可视化)是数据分析的核心呈现载体,它将抽象的数据转化为直观的图表、图形,让数据规律、业务差异与潜在问题一目 ...
2026-01-29箱线图(Box Plot)作为数据分布可视化的核心工具,能清晰呈现数据的中位数、四分位数、异常值等关键统计特征,广泛应用于数据分 ...
2026-01-28在回归分析、机器学习建模等数据分析场景中,多重共线性是高频数据问题——当多个自变量间存在较强的线性关联时,会导致模型系数 ...
2026-01-28数据分析的价值落地,离不开科学方法的支撑。六种核心分析方法——描述性分析、诊断性分析、预测性分析、规范性分析、对比分析、 ...
2026-01-28在机器学习与数据分析领域,特征是连接数据与模型的核心载体,而特征重要性分析则是挖掘数据价值、优化模型性能、赋能业务决策的 ...
2026-01-27关联分析是数据挖掘领域中挖掘数据间潜在关联关系的经典方法,广泛应用于零售购物篮分析、电商推荐、用户行为路径挖掘等场景。而 ...
2026-01-27数据分析的基础范式,是支撑数据工作从“零散操作”走向“标准化落地”的核心方法论框架,它定义了数据分析的核心逻辑、流程与目 ...
2026-01-27在数据分析、后端开发、业务运维等工作中,SQL语句是操作数据库的核心工具。面对复杂的表结构、多表关联逻辑及灵活的查询需求, ...
2026-01-26支持向量机(SVM)作为机器学习中经典的分类算法,凭借其在小样本、高维数据场景下的优异泛化能力,被广泛应用于图像识别、文本 ...
2026-01-26