
CDA數(shù)據(jù)分析師 出品
作者:真達(dá)、Mika
數(shù)據(jù):真達(dá)
【導(dǎo)讀】今天的內(nèi)容是一期python實(shí)戰(zhàn)訓(xùn)練,我們來手把手教你用Python分析保險(xiǎn)產(chǎn)品交叉銷售和哪些因素有關(guān)。
01、實(shí)戰(zhàn)背景
首先介紹下實(shí)戰(zhàn)的背景, 這次的數(shù)據(jù)集來自kaggle:
https://www.kaggle.com/anmolkumar/health-insurance-cross-sell-prediction
我們的客戶是一家保險(xiǎn)公司,最近新推出了一款汽車保險(xiǎn)。現(xiàn)在他們的需要是建立一個(gè)模型,用來預(yù)測(cè)去年的投保人是否會(huì)對(duì)這款汽車保險(xiǎn)感興趣。
我們知道,保險(xiǎn)單指的是,保險(xiǎn)公司承諾為特定類型的損失、損害、疾病或死亡提供賠償保證,客戶則需要定期向保險(xiǎn)公司支付一定的保險(xiǎn)費(fèi)。這里再進(jìn)一步說明一下。
例如,你每年要為20萬的健康保險(xiǎn)支付2000元的保險(xiǎn)費(fèi)。那么你肯定會(huì)想,保險(xiǎn)公司只收取5000元的保費(fèi),這種情況下,怎么能承擔(dān)如此高的住院費(fèi)用呢? 這時(shí),“概率”的概念就出現(xiàn)了。例如,像你一樣,可能有100名客戶每年支付2000元的保費(fèi),但當(dāng)年住院的可能只有少數(shù)人,(比如2-3人),而不是所有人。通過這種方式,每個(gè)人都分擔(dān)了其他人的風(fēng)險(xiǎn)。
和醫(yī)療保險(xiǎn)一樣,買了車險(xiǎn)的話,每年都需要向保險(xiǎn)公司支付一定數(shù)額的保險(xiǎn)費(fèi),這樣在車輛發(fā)生意外事故時(shí),保險(xiǎn)公司將向客戶提供賠償(稱為“保險(xiǎn)金額”)。
我們要做的就是建立模型,來預(yù)測(cè)客戶是否對(duì)汽車保險(xiǎn)感興趣。這對(duì)保險(xiǎn)公司來說是非常有幫助的,公司可以據(jù)此制定溝通策略,接觸這些客戶,并優(yōu)化其商業(yè)模式和收入。
02、數(shù)據(jù)理解
為了預(yù)測(cè)客戶是否對(duì)車輛保險(xiǎn)感興趣,我們需要了解一些客戶信息 (性別、年齡等)、車輛(車齡、損壞情況)、保單(保費(fèi)、采購(gòu)渠道)等信息。
數(shù)據(jù)劃分為訓(xùn)練集和測(cè)試集,訓(xùn)練數(shù)據(jù)包含381109筆客戶資料,每筆客戶資料包含12個(gè)字段,1個(gè)客戶ID字段、10個(gè)輸入字段及1個(gè)目標(biāo)字段-Response是否響應(yīng)(1代表感興趣,0代表不感興趣)。測(cè)試數(shù)據(jù)包含127037筆客戶資料;字段個(gè)數(shù)與訓(xùn)練數(shù)據(jù)相同,目標(biāo)字段沒有值。字段的定義可參考下文。
下面我們開始吧!
03、數(shù)據(jù)讀入和預(yù)覽
首先開始數(shù)據(jù)讀入和預(yù)覽。
# 數(shù)據(jù)整理 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 # 自定義
# 讀入訓(xùn)練集 train = pd.read_csv('../data/train.csv') train.head()
# 讀入測(cè)試集 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、探索性分析
下面,我們基于訓(xùn)練數(shù)據(jù)集進(jìn)行探索性數(shù)據(jù)分析。
1. 描述性分析
首先對(duì)數(shù)據(jù)集中數(shù)值型屬性進(jìn)行描述性統(tǒng)計(jì)分析。
desc_table = train.drop(['id', 'Vehicle_Age'], axis=1).describe().T desc_table
通過描述性分析后,可以得到以下結(jié)論。從以上描述性分析結(jié)果可以得出:
2. 目標(biāo)變量的分布
訓(xùn)練集共有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/目標(biāo)變量分布.html')
3. 性別因素
從條形圖可以看出,男性的客戶群體對(duì)汽車保險(xiǎn)感興趣的概率稍高,是13.84%,相較女性客戶高出3個(gè)百分點(diǎn)。
pd.crosstab(train['Gender'], train['Response'])
# 實(shí)例類 eda = EDAnalysis(data=train, id_col='id', target='Response') # 柱形圖 fig = eda.draw_bar_stack_cat(colname='Gender') pyplot(fig, filename='./html/性別與是否感興趣.html')
4. 之前是否投保
沒有購(gòu)買汽車保險(xiǎn)的客戶響應(yīng)概率更高,為22.54%,有購(gòu)買汽車保險(xiǎn)的客戶則沒有這一需求,感興趣的概率僅為0.09%。
pd.crosstab(train['Previously_Insured'], train['Response'])
fig = eda.draw_bar_stack_cat(colname='Previously_Insured') pyplot(fig, filename='./html/之前是否投保與是否感興趣.html')
5. 車齡因素
車齡越大,響應(yīng)概率越高,大于兩年的車齡感興趣的概率最高,為29.37%,其次是1~2年車齡,概率為17.38%。小于1年的僅為4.37%。
6. 車輛損壞情況
車輛曾經(jīng)損壞過的客戶有較高的響應(yīng)概率,為23.76%,相比之下,客戶過去車輛沒有損壞的響應(yīng)概率僅為0.52%
7. 不同年齡
從直方圖中可以看出,年齡較高的群體和較低的群體響應(yīng)的概率較低,30~60歲之前的客戶響應(yīng)概率較高。通過可視化探索,我們大致可以知道:
車齡在1年以上,之前有車輛損壞的情況出現(xiàn),且未購(gòu)買過車輛保險(xiǎn)的客戶有較高的響應(yīng)概率。
此部分工作主要包含字段選擇,數(shù)據(jù)清洗和數(shù)據(jù)編碼,字段的處理如下:
# 刪除字段 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 # 數(shù)據(jù)編碼 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()
測(cè)試集做相同的處理:
# 刪除字段 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 # 數(shù)據(jù)編碼 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()
我們選擇使用以下幾種模型進(jìn)行建置,并比較模型的分類效能。首先在將訓(xùn)練集劃分為訓(xùn)練集和驗(yàn)證集,其中訓(xùn)練集用于訓(xùn)練模型,驗(yàn)證集用于驗(yàn)證模型效果。首先導(dǎo)入建模庫(kù):
# 建模 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 # 預(yù)處理 from sklearn.preprocessing import StandardScaler, MinMaxScaler # 模型評(píng)估 from sklearn.model_selection import train_test_split, GridSearchCV from sklearn.metrics import confusion_matrix, classification_report, accuracy_score, f1_score, roc_auc_score
# 劃分特征和標(biāo)簽 X = train.drop(['id', 'Response'], axis=1) y = train['Response'] # 劃分訓(xùn)練集和驗(yàn)證集(分層抽樣) 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,)
# 處理樣本不平衡,對(duì)0類樣本進(jìn)行降采樣 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) # 保存一份極值標(biāo)準(zhǔn)化的數(shù)據(jù) 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) # 測(cè)試集 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
# 對(duì)測(cè)試集評(píng)估 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. 隨機(jī)森林
# 決策樹 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作為評(píng)價(jià)標(biāo)準(zhǔn)的情況下,KNN算法有較好的分類效能,這可能是由于數(shù)據(jù)樣本本身不平衡導(dǎo)致,后續(xù)可以通過其他類別不平衡的方式做進(jìn)一步處理,同時(shí)可以通過參數(shù)調(diào)整的方式來優(yōu)化其他模型,通過調(diào)整預(yù)測(cè)的門檻值來增加預(yù)測(cè)效能等其他方式。
——熱門課程推薦:
想學(xué)習(xí)PYTHON數(shù)據(jù)分析與金融數(shù)字化轉(zhuǎn)型精英訓(xùn)練營(yíng),您可以點(diǎn)擊>>>“人才轉(zhuǎn)型”了解課程詳情;
想從事業(yè)務(wù)型數(shù)據(jù)分析師,您可以點(diǎn)擊>>>“數(shù)據(jù)分析師”了解課程詳情;
想從事大數(shù)據(jù)分析師,您可以點(diǎn)擊>>>“大數(shù)據(jù)就業(yè)”了解課程詳情;
想成為人工智能工程師,您可以點(diǎn)擊>>>“人工智能就業(yè)”了解課程詳情;
想了解Python數(shù)據(jù)分析,您可以點(diǎn)擊>>>“Python數(shù)據(jù)分析師”了解課程詳情;
想咨詢互聯(lián)網(wǎng)運(yùn)營(yíng),你可以點(diǎn)擊>>>“互聯(lián)網(wǎng)運(yùn)營(yíng)就業(yè)班”了解課程詳情;
數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼
若不方便掃碼,搜微信號(hào):CDAshujufenxi
SQL Server 中 CONVERT 函數(shù)的日期轉(zhuǎn)換:從基礎(chǔ)用法到實(shí)戰(zhàn)優(yōu)化 在 SQL Server 的數(shù)據(jù)處理中,日期格式轉(zhuǎn)換是高頻需求 —— 無論 ...
2025-09-18MySQL 大表拆分與關(guān)聯(lián)查詢效率:打破 “拆分必慢” 的認(rèn)知誤區(qū) 在 MySQL 數(shù)據(jù)庫(kù)管理中,“大表” 始終是性能優(yōu)化繞不開的話題。 ...
2025-09-18CDA 數(shù)據(jù)分析師:表結(jié)構(gòu)數(shù)據(jù) “獲取 - 加工 - 使用” 全流程的賦能者 表結(jié)構(gòu)數(shù)據(jù)(如數(shù)據(jù)庫(kù)表、Excel 表、CSV 文件)是企業(yè)數(shù)字 ...
2025-09-18DSGE 模型中的 Et:理性預(yù)期算子的內(nèi)涵、作用與應(yīng)用解析 動(dòng)態(tài)隨機(jī)一般均衡(Dynamic Stochastic General Equilibrium, DSGE)模 ...
2025-09-17Python 提取 TIF 中地名的完整指南 一、先明確:TIF 中的地名有哪兩種存在形式? 在開始提取前,需先判斷 TIF 文件的類型 —— ...
2025-09-17CDA 數(shù)據(jù)分析師:解鎖表結(jié)構(gòu)數(shù)據(jù)特征價(jià)值的專業(yè)核心 表結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 規(guī)范存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如數(shù)據(jù)庫(kù)表、Excel 表、 ...
2025-09-17Excel 導(dǎo)入數(shù)據(jù)含缺失值?詳解 dropna 函數(shù)的功能與實(shí)戰(zhàn)應(yīng)用 在用 Python(如 pandas 庫(kù))處理 Excel 數(shù)據(jù)時(shí),“缺失值” 是高頻 ...
2025-09-16深入解析卡方檢驗(yàn)與 t 檢驗(yàn):差異、適用場(chǎng)景與實(shí)踐應(yīng)用 在數(shù)據(jù)分析與統(tǒng)計(jì)學(xué)領(lǐng)域,假設(shè)檢驗(yàn)是驗(yàn)證研究假設(shè)、判斷數(shù)據(jù)差異是否 “ ...
2025-09-16CDA 數(shù)據(jù)分析師:掌控表格結(jié)構(gòu)數(shù)據(jù)全功能周期的專業(yè)操盤手 表格結(jié)構(gòu)數(shù)據(jù)(以 “行 - 列” 存儲(chǔ)的結(jié)構(gòu)化數(shù)據(jù),如 Excel 表、數(shù)據(jù) ...
2025-09-16MySQL 執(zhí)行計(jì)劃中 rows 數(shù)量的準(zhǔn)確性解析:原理、影響因素與優(yōu)化 在 MySQL SQL 調(diào)優(yōu)中,EXPLAIN執(zhí)行計(jì)劃是核心工具,而其中的row ...
2025-09-15解析 Python 中 Response 對(duì)象的 text 與 content:區(qū)別、場(chǎng)景與實(shí)踐指南 在 Python 進(jìn)行 HTTP 網(wǎng)絡(luò)請(qǐng)求開發(fā)時(shí)(如使用requests ...
2025-09-15CDA 數(shù)據(jù)分析師:激活表格結(jié)構(gòu)數(shù)據(jù)價(jià)值的核心操盤手 表格結(jié)構(gòu)數(shù)據(jù)(如 Excel 表格、數(shù)據(jù)庫(kù)表)是企業(yè)最基礎(chǔ)、最核心的數(shù)據(jù)形態(tài) ...
2025-09-15Python HTTP 請(qǐng)求工具對(duì)比:urllib.request 與 requests 的核心差異與選擇指南 在 Python 處理 HTTP 請(qǐng)求(如接口調(diào)用、數(shù)據(jù)爬取 ...
2025-09-12解決 pd.read_csv 讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)的科學(xué)計(jì)數(shù)法問題 為幫助 Python 數(shù)據(jù)從業(yè)者解決pd.read_csv讀取長(zhǎng)浮點(diǎn)數(shù)據(jù)時(shí)的科學(xué)計(jì)數(shù)法問題 ...
2025-09-12CDA 數(shù)據(jù)分析師:業(yè)務(wù)數(shù)據(jù)分析步驟的落地者與價(jià)值優(yōu)化者 業(yè)務(wù)數(shù)據(jù)分析是企業(yè)解決日常運(yùn)營(yíng)問題、提升執(zhí)行效率的核心手段,其價(jià)值 ...
2025-09-12用 SQL 驗(yàn)證業(yè)務(wù)邏輯:從規(guī)則拆解到數(shù)據(jù)把關(guān)的實(shí)戰(zhàn)指南 在業(yè)務(wù)系統(tǒng)落地過程中,“業(yè)務(wù)邏輯” 是連接 “需求設(shè)計(jì)” 與 “用戶體驗(yàn) ...
2025-09-11塔吉特百貨孕婦營(yíng)銷案例:數(shù)據(jù)驅(qū)動(dòng)下的精準(zhǔn)零售革命與啟示 在零售行業(yè) “流量紅利見頂” 的當(dāng)下,精準(zhǔn)營(yíng)銷成為企業(yè)突圍的核心方 ...
2025-09-11CDA 數(shù)據(jù)分析師與戰(zhàn)略 / 業(yè)務(wù)數(shù)據(jù)分析:概念辨析與協(xié)同價(jià)值 在數(shù)據(jù)驅(qū)動(dòng)決策的體系中,“戰(zhàn)略數(shù)據(jù)分析”“業(yè)務(wù)數(shù)據(jù)分析” 是企業(yè) ...
2025-09-11Excel 數(shù)據(jù)聚類分析:從操作實(shí)踐到業(yè)務(wù)價(jià)值挖掘 在數(shù)據(jù)分析場(chǎng)景中,聚類分析作為 “無監(jiān)督分組” 的核心工具,能從雜亂數(shù)據(jù)中挖 ...
2025-09-10統(tǒng)計(jì)模型的核心目的:從數(shù)據(jù)解讀到?jīng)Q策支撐的價(jià)值導(dǎo)向 統(tǒng)計(jì)模型作為數(shù)據(jù)分析的核心工具,并非簡(jiǎn)單的 “公式堆砌”,而是圍繞特定 ...
2025-09-10