保险产品交叉销售相关因素分析

一、项目背景

项目实战背景, 数据集来自kaggle:https://www.kaggle.com/anmolkumar/health-insurance-cross-sell-prediction

保险公司最近新推出了一款汽车保险,想知道去年的投保人是否会对这款汽车保险感兴趣,以便有针对性的进行推广销售。我们要做的是建立模型,来预测客户是否对汽车保险感兴趣。这对保险公司来说是非常有帮助的,保险公司可以据此制定沟通策略,接触这些客户,并优化其商业模式和收入。

这里介绍下保险的概念,保险单指的是,保险公司承诺为特定类型的损失、损害、疾病或死亡提供赔偿保证,客户则需要定期向保险公司支付一定的保险费。和医疗保险一样,买了车险的话,每年都需要向保险公司支付一定数额的保险费,这样在车辆发生意外事故时,保险公司将向客户提供赔偿(称为“保险金额”)。

二、数据探索

2.1数据理解

为了预测客户是否对车辆保险感兴趣,我们需要了解一些客户信息 (性别、年龄等)、车辆(车龄、损坏情况)、保单(保费、采购渠道)等信息。

数据划分为训练集和测试集,训练数据包含381109笔客户资料,每笔客户资料包含12个字段,1个客户ID字段、10个输入字段及1个目标字段-Response是否响应(1代表感兴趣,0代表不感兴趣)。测试数据包含127037笔客户资料;字段个数与训练数据相同,目标字段没有值。字段的定义可参考下文。

2.2数据读入

# 读入训练集

train= pd.read_csv('train.csv')

# 读入测试集

test= pd.read_csv('test.csv')

print("查看基本信息")

print(train.info())

print(train.shape)

2.3探索性分析

下面,我们基于训练数据集进行探索性数据分析。

2.3.1描述性分析

首先对数据集中数值型属性进行描述性统计分析。

desc_table = train.drop(['id''], axis=1).describe().T

 通过描述性分析后,可以得到以下结论。从以上描述性分析结果可以得出:

客户年龄:客户的年龄范围在20 ~ 85岁之间,平均年龄是38岁,青年群体居多;

是否有驾照:99.89%客户都持有驾照;

之前是否投保:45.82%的客户已经购买了车辆保险;

年度保费:客户的保费范围在2630 ~ 540165之间,平均的保费金额是30564。

往来时长:此数据基于过去一年的数据,客户的往来时间范围在10~299天之间,平均往来时长为154天。

是否响应:平均来看,客户对车辆保险感兴趣的概率为12.25%。

2.3.2 可视化分析

2.3.2.1目标变量的分布

训练集共有381109笔客户资料,其中感兴趣的有46710人,占比12.3%,不感兴趣的有334399人,占比87.7%。

目标变量分布.png

values= train['Response'].value_counts().values.tolist()

plt.pie(values,labels=['Not interested','Interested'],startangle=90,autopct='%1.1f%%')

plt.legend(loc="upper right")

plt.savefig('explore/目标变量分布.png')

2.3.2.2性别因素

从条形图可以看出,男性的客户群体对汽车保险感兴趣的概率稍高,是13.84%,相较女性客户高出3个百分点。

性别因素-目标.png

print("Gender:\n",train['Gender'].value_counts())

data_Gender=train.groupby(['Gender','Response'])['Response'].count().unstack()

data_Gender['interestedRate']=data_Gender[1]/(data_Gender[1]+data_Gender[0])

f,ax1=plt.subplots(figsize=(16,9))

data_Gender[[0,1]].plot(kind='bar',ax=ax1,rot=0,fontsize=14)

ax2=ax1.twinx()

data_Gender['interestedRate'].plot(ax=ax2,style='g.-',fontsize=14)

plt.title('Response by Gender',fontsize=20)

ax1.set_xlabel('Gender',fontsize=16)

ax1.set_ylabel('Count',fontsize=16)

ax2.set_ylabel('interestRate',fontsize=16)

ax2.legend(loc='center right',fontsize=14)

ax1.legend(fontsize=14)

plt.savefig("explore/Gender-Response.png")

2.3.2.3之前是否投保

没有购买汽车保险的客户响应概率更高,为22.54%,有购买汽车保险的客户则没有这一需求,感兴趣的概率仅为0.09%。

之前是否投保-目标.png

data_Previously_Insured=train.groupby(['Previously_Insured','Response'])['Response'].count().unstack()

data_Previously_Insured['interestedRate']=data_Previously_Insured[1]/(data_Previously_Insured[1]+data_Previously_Insured[0])

f,ax1=plt.subplots(figsize=(16,9))

data_Previously_Insured[[0,1]].plot(kind='bar',ax=ax1,rot=0,fontsize=14)

ax2=ax1.twinx()

data_Previously_Insured['interestedRate'].plot(ax=ax2,style='g.-',fontsize=14)

plt.title('Response by Previously_Insured',fontsize=20)

ax1.set_xlabel('Previously_Insured',fontsize=16)

ax1.set_ylabel('Count',fontsize=16)

ax2.set_ylabel('interestRate',fontsize=16)

ax2.legend(loc='center right',fontsize=14)

ax1.legend(fontsize=14)

plt.savefig("explore/Previously_Insured-Response.png")

2.3.2.4车龄因素

车龄越大,响应概率越高,大于两年的车龄感兴趣的概率最高,为29.37%,其次是1~2年车龄,概率为17.38%。小于1年的仅为4.37%。

车龄-目标.png

2.3.2.5车辆损坏情况

车辆曾经损坏过的客户有较高的响应概率,为23.76%,相比之下,客户过去车辆没有损坏的响应概率仅为0.26%。

车辆损坏-目标.png

2.3.2.6. 不同年龄

从直方图中可以看出,年龄较高的群体和较低的群体响应的概率较低,30~60岁之前的客户响应概率较高。80-85以上是最感兴趣的。

年龄-目标.png

temp= pd.DataFrame()

temp1= pd.cut(train.loc[train['Response']==0,'Age'],15).value_counts()

Index= pd.cut(train.loc[train['Response']==0,'Age'],15).value_counts().index

temp1.reset_index(drop=True,inplace=True)

temp2= pd.cut(train.loc[train['Response']==1,'Age'],15).value_counts()

temp2.reset_index(drop=True,inplace=True)

temp= pd.concat([temp1,temp2],axis=1)

temp.columns= ['not interest',"interest"]

temp['interestRate']=temp['interest']/(temp['interest']+temp['not interest'])

temp.index= Index

f,ax=plt.subplots(figsize=(16,9))

_list= []

_list2= []

print(type(pd.cut(train.loc[train['Response']==0,'Age'],15).iloc[:-1]),

pd.cut(train.loc[train['Response']==0,'Age'],15).iloc[:-1].count())

for i,vin pd.cut(train.loc[train['Response']==0,'Age'],15).iloc[:-1].items():

    _list.append(v.left)

_list.append(v.right)

_list2.append((v.left+v.right)/2)

_list= sorted(list(set(_list)))

_list2= sorted(list(set(_list2)))

print(_list,len(_list))

print(_list2,len(_list2))

train.loc[(train['Response']==0),'Age'].plot(xticks =_list,

kind='hist',bins=15,ax=ax,label='not interest')

train.loc[(train['Response']==1),'Age'].plot(xticks =_list,

kind='hist',bins=15,ax=ax,label='interest')

ax.legend(loc='best',fontsize=14)

ax2.legend(loc='center right',fontsize=14)

ax2=ax.twinx()

ax2.plot(_list2,temp['interestRate'].values.tolist(),"green")

ax.set_title('Response by Age',fontsize=20)

ax.set_xlabel('Age',fontsize=16)

ax.set_ylabel('Count',fontsize=16)

ax2.set_ylabel('interestRate',fontsize=16)

plt.savefig('explore/Age-Response.png')

三、数据预处理

此部分工作主要包含字段选择,数据清洗和数据编码,字段的处理如下:

Annual_Premium:异常值处理

Gender、Vehicle_Age、Vehicle_Damage:分类型数据转换为数值型编码

# 盖帽法处理异常值

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

四、数据建模

处理样本不平衡,对0类样本进行降采样

from imblearn.under_samplingimport RandomUnderSampler

under_model= RandomUnderSampler(sampling_strategy={0:133759,1:37368},random_state=0)

X, y= under_model.fit_sample(X, y)

print("下采样后的数据",y.value_counts())

X_train, X_val, y_train, y_val= train_test_split(X, y,test_size=0.2,stratify=y,random_state=0)

数据归一化

from sklearn.preprocessingimport StandardScaler, MinMaxScaler

mms= MinMaxScaler()

X_train_scaled= pd.DataFrame(mms.fit_transform(X_train),columns=X.columns)

X_val_scaled= pd.DataFrame(mms.transform(X_val),columns=X.columns)

print("归一化的数据:\n",X_train_scaled.head())

KNN算法,使用学习曲线得到最优k值8,最优准确率0.781

k学习曲线.png

knn_scores= []

for iin range(3,10,1):

    knn= KNeighborsClassifier(n_neighbors=i,n_jobs=-1)

knn.fit(X_train_scaled, y_train)

y_pred= knn.predict(X_val_scaled)

knn_scores.append(accuracy_score(y_true=y_val,y_pred=y_pred))

plt.figure(figsize=(10,10))

plt.plot(range(3,10,1),knn_scores)

plt.title("knn_scores by k")

plt.savefig("explore/knn_scores.png")

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • pandas 数据分析【转】 frompandasimportSeries, DataFrameimportpan...
    gongdiwudu阅读 1,498评论 0赞 1
  • Python Data Anlysis NotebookSublimeText FileData FrameIte...
    生煎小包阅读 869评论 0赞 1
  • 项目介绍: p2p 借贷业务具有门槛低,渠道成本低的特性,风险防控对于出借企业来说非常重要。本项目需要 从大量借贷...
    autumn的数据分析阅读 2,396评论 0赞 3
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 8,218评论 16赞 22
  • 今天感恩节哎,感谢一直在我身边的亲朋好友。感恩相遇!感恩不离不弃。 中午开了第一次的党会,身份的转变要...
    余生动听阅读 11,124评论 0赞 11

友情链接更多精彩内容