# 商業智慧分析Final Project ###### tags: `商業智慧分析` :::warning :bulb: **final_data.csv資料概述-保險資料** 目標:找出和顧客終身價值(CLV)有關的變數 * Insight 1:建議集中在月初月中販售保險 * Insight 2:Coverage_Premium的CLV較高,穩固投入該客群 * Insight 3:disable的CLV較高,著重投入拓展該市場 * Insight 4:離婚族群的CLV較高,著重投入離婚族群客群 * Insight 5:Luxury SUV中Large Size客戶CLV較高,投入該市場 * Insight 6:每月自動轉換保費對顧客終身價值間具有正向效果 ::: ## 資料預處理 ### Step 1 Improt套件 匯入pandas和matplotlib以進行資料處理與視覺化 ```=py import pandas as pd import matplotlib.pyplot as plt %matplotlib inline plt.show() #告訴後台畫的圖可以直接顯示出來 ``` ### Step 2 匯入資料 將名為"final_data.csv"的檔案匯入成為df ```=py df=pd.read_csv("final_data.csv") ``` ### Step 3 觀察資料的長相 **(1) 觀察首10行的資料** ```=py df.head(10)_ ``` ![](https://i.imgur.com/mWh5tsr.png) **(2) 並且觀察有哪些欄位** ```=py df.columns ``` ![](https://i.imgur.com/j1qkJIT.png) **(3) 欄位翻譯** | Customer | State | Customer Lifetime Value | Response | Coverage | Education | | -------- | -------- | -------- | -------- | -------- | -------- | | 顧客ID | 地區 | 顧客終身價值 | 回覆 | 保費 | 教育程度 | | Effective To Date | EmploymentStatus | Gender | Income | Location Code | Marital Status | | 保險生效日期 | 工作狀態 | 性別 | 收入 | 居住地段 | 婚姻狀態 | | Monthly Premium Auto | Months Since Last Claim | Months Since Policy Inception | Number of Open Complaints | Number of Policies | Policy Type | | 每月自動轉換保費| 上次申請保險 | 保險生效日 | 客訴次數 | 條款內保險數量 | 保險類別 | | Policy | Renew Offer Type | Sales Channel |Total Claim Amount | Vehicle Class |Vehicle Size | | 保險等級| 續約方式 | 購買渠道 | 總賠償金額 | 汽車類型|汽車大小 | ### Step 4 處理遺漏值 **(1) 觀察資料的shape** ```=py df.shape ``` ![](https://i.imgur.com/4zTKl2S.png) **(2) 確認有無遺漏值** ```=py df.notnull().sum() #沒有missing data ``` ![](https://i.imgur.com/SOuZtHc.png) ```=py df.isnull().sum() #發現一堆空格 ``` ![](https://i.imgur.com/uGQmLC0.png) 除去空格並且檢查shape ```=py df.dropna(how="any",inplace=True) df.shape ``` ![](https://i.imgur.com/BGIclS4.png) **(2) 確認有無重複值** ```=py df.Customer.nunique() #確定沒有重複的人 ``` ![](https://i.imgur.com/KUPfS4m.png) ### Step 5 整理資料欄位 **(1) 置換有空格的欄位並重新命名** ```=py df.rename(columns={'Customer Lifetime Value':'Customer_Lifetime_Value',"Effective To Date":"Effective_To_Date","Location Code":"Location_Code","Marital Status":"Marital_Status","Monthly Premium Auto":"Monthly_Premium_Auto","Months Since Last Claim":"Months_Since_Last_Claim","Months Since Policy Inception":"Months_Since_Policy_Inception","Number of Open Complaints":"Number_of_Open_Complaints","Number of Policies":"Number_of_Policies","Policy Type":"Policy_Type","Renew Offer Type":"Renew_Offer_Type","Sales Channel":"Sales_Channel","Total Claim Amount":"Total_Claim_Amount","Vehicle Class":"Vehicle_Class","Vehicle Size":"Vehicle_Size"}, inplace=True) ``` **(2) 檢查資料dtype** ```=py df.dtypes ``` ![](https://i.imgur.com/dOC3VG9.png) **(3) 觀察欄位內容** 運用value_counts()觀察object欄位內資料分布 **<font color="#f00">目的 $\rightarrow$ 獲得分析想法 </font>** 1. 地區 ```=py df["State"].value_counts() #觀察資料都來自哪些州 #大多都來自Oregon,California ``` ![](https://i.imgur.com/virT4kI.png) 2. 回覆 ```=py df["Response"].value_counts() #觀察保險回覆的狀況 #大部分都沒有報過保險 ``` ![](https://i.imgur.com/9zZXsxk.png) 3. 保費 ```=py df["Coverage"].value_counts() #保費的分布 #大部分的人都保Basic ``` ![](https://i.imgur.com/VoSdidX.png) :::info :information_source: **想法 1** 1. 可以研究看看收入和保費是不是有關係 2. 收入和顧客終身價值(CLV)是不是有關係 3. 保費和顧客終身價值(CLV)是不是有關係 ::: 4. 教育程度 ```=py df["Education"].value_counts() #教育程度的分布 #大部分的人都是大學生 ``` ![](https://i.imgur.com/9c565xh.png) 5. 工作狀態 ```=py df["EmploymentStatus"].value_counts() #就業狀況 #大部分都在職 ``` ![](https://i.imgur.com/6xfLe0b.png) :::info :information_source: **想法 2** 1. 在職的人會比較多顧客終身價值還是比較少? 2. 想知道退休或是disable的人是不是有比較多的顧客終身價值 ::: 6. 性別 ```=py df["Gender"].value_counts() #性別分布算平均,女生比較多 ``` ![](https://i.imgur.com/FOAcVcc.png) 7. 居住地段 ```=py df["Location_Code"].value_counts() #住在哪裡 #大多數人都住在市郊 ``` ![](https://i.imgur.com/y95U7h0.png) 8. 婚姻狀況 ```=py df["Marital_Status"].value_counts() #婚姻狀況 #大部分的人都結婚了 ``` ![](https://i.imgur.com/4mW6aNT.png) :::info :information_source: **想法 3** 1. 結婚的人會有比較高的顧客終身價值(CLV)嗎? ::: 9. 保險類別 ```=py df["Policy_Type"].value_counts() #是哪種類型保險 #大多數為個人險 ``` ![](https://i.imgur.com/nQpAZ5L.png) 10. 保險等級 ```=py df["Policy"].value_counts() #保險類型的分類 #最多人保Personal L3 ``` ![](https://i.imgur.com/aXXL4g9.png) 11. 續約方式 ```=Py df["Renew_Offer_Type"].value_counts() #續約方式 #offer1最多 ``` ![](https://i.imgur.com/ovWWuwn.png) 12. 購買渠道 ```=py df["Sales_Channel"].value_counts() #購買渠道 #大多數人透過保險業務員買的 ``` ![](https://i.imgur.com/1eZQsN5.png) 13. 汽車類型 ```=py df["Vehicle_Class"].value_counts() #開的車的種類 #大部分人開四門車 ``` ![](https://i.imgur.com/9rhkfLB.png) :::info :information_source: **想法 4** 1. 車種和顧客終身價值(CLV)的關係 ::: 14. 汽車大小 ```=py df["Vehicle_Size"].value_counts() #車的大小 #大部分人開中等大小的車 ``` ![](https://i.imgur.com/TjFG253.png) **(4) 轉換Dummy Variable** 1. 轉換Dummy Variable ```=py df2=pd.get_dummies(df,columns=["State","Response","Coverage","Education","EmploymentStatus","Gender","Location_Code","Marital_Status","Policy_Type","Policy","Renew_Offer_Type","Sales_Channel","Vehicle_Class","Vehicle_Size"],drop_first=True) #把這些項目轉換成dummy variable ``` 2. 確認轉換後的欄位 ```=py df2.columns ``` ![](https://i.imgur.com/EsaFl3g.png) ```=py df2.dtypes #確認有轉換成功 ``` ![](https://i.imgur.com/uR5nIOL.png) **(5) 轉換時間** 1. 將保險生效日轉換 ```=py df2["time"]=pd.to_datetime(df2["Effective_To_Date"]) #將保險生效日轉換成日期可處理的模式 ``` 2. 確認轉換成功 ```=py df2.dtypes #確認轉換成功 ``` ![](https://i.imgur.com/BgBOjzn.png) 3. 確認資料起迄日 ```=py df2.time.min() df2.time.max() df2.time.max()-df2.time.min() #資料起投到借書的時間為58日,從2011/1/1-2011/2/28 ``` ![](https://i.imgur.com/BwHqNWM.png) ![](https://i.imgur.com/NHOWvrO.png) ![](https://i.imgur.com/p4YzacW.png) 4. 觀察購買保險的日期 ```=py df2["day"]=df2.time.dt.day df2.day.value_counts() df2.day.value_counts().sort_index().plot() #可以看到大家月底的時候都不太購買保險 #有可能是月底大家都比較沒錢 ``` ![](https://i.imgur.com/2u9DUAp.png) :::success :bulb: **Insight 1** 1. 觀察到在月底的時候銷量都不是很好 2. <font color="#f00">得出結論:建議集中在月初月中販售保險</font> ::: ### Step 6 資料標準化 **(1) 變數標準化處理** 將變數進行標準化處理 並且創建出一個新的**df_z**儲存標準化後的變數 ```=py def z_score_normalized(colName): mu=df_float[colName].mean() std=df_float[colName].std() z_score_normalized=(df_float[colName]-mu)/std return z_score_normalized df_z=df.select_dtypes(include="float64")#篩選出float64型態的資料進行標準化-->df_z for i in df_z: df_z[i]=z_score_normalized(i)#將標準化後的資料直接放入df_z df_z ``` ![](https://i.imgur.com/wUA0ZDR.png) ## 資料分析 ### Step 1 處理想法1 首先瞭解一下Income的情況 並且將其視覺化處理 ```=py df["Income"].describe() #了解一下收入的情況 ``` ![](https://i.imgur.com/iQupxKq.png) **(1) 直方圖-瞭解分布** ```=py ax=df["Income"].plot.hist(bins=50) ax.set_title("Income plot")#將圖命名 ax.set_xlabel("Income")#將x軸命名 ax.set_ylabel("prople number")#將y軸命名 fig=ax.figure#生出圖 fig.set_size_inches(8,3)#圖的大小 fig.tight_layout(pad=1)#自動調整布局 plt.show()#做出圖 #看一下大家的收入分布 ``` ![](https://i.imgur.com/OUxAtIy.png) 發現有一大群人是沒有收入的 **(2) 盒鬚圖-觀察有無離群值** ```=py ax=df["Income"].plot.box(vert=True) ax.set_title("Income plot")#將圖命名 ax.set_xlabel("Income")#將x軸命名 ax.set_ylabel("prople number")#將y軸命名 fig=ax.figure#生出圖 fig.set_size_inches(8,3)#圖的大小 fig.tight_layout(pad=1)#自動調整布局 plt.show()#做出圖 #看一下有沒有離群值 ``` ![](https://i.imgur.com/SEpgbn7.png) 沒有離群值 **(3) 處理想法1.1(保費-收入)** 以groupby將保費分群觀察收入mean的差別 ```=py df.groupby("Coverage").Income.describe() #想要了解一下收入和保費有沒有關係 ``` ![](https://i.imgur.com/WDhyQr5.png) 發現不論是在Basic、Extended、Premium中收入表現都差不多 ==因此,收入和保費沒有太多的關係== **(4) 處理想法1.2(收入-顧客終身價值)** 導入STATISITCAL MODEL觀察變數間線性關係 ```=py #STATISITCAL MODEL import statsmodels.api as sm from statsmodels.formula.api import ols ``` 運用OLS迴歸處理收入和顧客終身價值 將顧客終身價值設為依變項(Y) 將收入設為自變項(X) ```=py #來看一下income是否可以預測clv y=df_z["Customer_Lifetime_Value"] x=df_z["Income"] model = ols("y ~ x", data=df_z).fit() print(model.summary()) ``` ![](https://i.imgur.com/9neRXm4.png) :::warning :bulb: **發現** 1. 可以看到pvalue小於0.05,Income可以顯著預測CLV ::: **(5) 處理想法1.3(保費-顧客終身價值)** 1. 運用OLS迴歸處理保費和顧客終身價值 將顧客終身價值設為依變項(Y) 將保費設為自變項(X) ```=py #來看一下Coverage是否可以預測clv y=df["Customer_Lifetime_Value"] x=df["Coverage"] model = ols("y ~ x", data=df).fit() print(model.summary()) ``` ![](https://i.imgur.com/jFmtfXw.png) 可以看到pvalue小於0.05,保費可以顯著預測CLV 2. 再來使用groupby將保費分群觀察CLV mean的差別 ```=py df.groupby("Coverage").Customer_Lifetime_Value.describe() ``` ![](https://i.imgur.com/lUIV3L4.png) :::success :bulb: **Insight 2** 1. 發現Basic的CLV是較低的,而Premium的CLV是高的 2. <font color="#f00">得出結論:因此我們應該要著重投入穩固Premium這群人</font> ::: ### Step 2 處理想法2 **(1) 首先瞭解一下工作狀態的分布** ```=py df["EmploymentStatus"].value_counts() #大家都有工作比較多 ``` ![](https://i.imgur.com/UHDHyn0.png) **(2) 以groupby將工作狀態分群觀察CLV mean的差別** ```=py df.groupby("EmploymentStatus").Customer_Lifetime_Value.describe() #有收入的人的確clv比較高-->合理 #有趣的是Disabled的人clv也算高 #Retired的人clv最低,最沒價值 ``` ![](https://i.imgur.com/GJTXSCS.png) Disabled的人CLV也算高,來觀察一下Disabled的薪水 **(3) 以groupby將工作狀態分群觀察收入 mean的差別** ```=py df.groupby("EmploymentStatus").Income.describe() #看一下收入和工作狀態的關係 #發現沒有收入的人就是Unemployed的人 #同時也發現Disabled的人士平均最低薪 #Employed平均最高薪-->合理 ``` ![](https://i.imgur.com/h0W7Ee8.png) Disabled的薪水最低 :::success :bulb: **Insight 3** 1. 有工作的人的確擁有最高的CLV 2. 退休的人擁有最低的CLV$\rightarrow$不值得投入 3. disable的人雖然低薪但是擁有較高的CLV$\rightarrow$推測失能的人較需要保險的需求 4. <font color="#f00">得出結論:因此我們應該要著重投入拓展disable市場</font> ::: ### Step 3 處理想法3 **(1) 首先瞭解一下婚姻狀態的分布** ```=py df["Marital_Status"].value_counts() #婚姻狀況 ``` ![](https://i.imgur.com/JPV0Vs2.png) **(2) 以groupby將婚姻狀態分群觀察CLV mean的差別** ```=py df.groupby("Marital_Status").Customer_Lifetime_Value.describe() ``` ![](https://i.imgur.com/19ybHqN.png) :::success :bulb: **Insight 4** 1. 離婚的人擁有最高的CLV$\rightarrow$有可能離婚的人比較注重財產保護 2. 結婚的人僅擁有次高的CLV 4. <font color="#f00">得出結論:因此我們應該要著重投入離婚族群市場</font> ::: ### Step 4 處理想法4 **(1) 首先瞭解一下汽車類型的分布** ```=py df["Vehicle_Class"].value_counts() #汽車類型分布 ``` ![](https://i.imgur.com/VqVnceC.png) **(2) 以groupby將汽車類型分群觀察CLV mean的差別** ``` df.groupby("Vehicle_Class").Customer_Lifetime_Value.describe() ``` ![](https://i.imgur.com/TmnllTZ.png) **(3) 以groupby將汽車類型、汽車大小分群觀察CLV mean的差別** 進一步看看是那一種車的車主CLV高 ```=py df.groupby(["Vehicle_Class","Vehicle_Size"]).Customer_Lifetime_Value.describe() #發現開Luxury SUV中大車的clv最高 #以後要鎖定Luxury SUV中大車的客戶 ``` ![](https://i.imgur.com/qeYSVW1.png) :::success :bulb: **Insight 5** 1. 開Luxury SUV的人CLV最高 2. 並且是Luxury SUV中Large Size的CLV最高 3. <font color="#f00">得出結論:因此我們應該要著重投入發掘Luxury SUV中Large Size客戶</font> ::: ### Step 5 想法1.3延伸-建立filter取出Premium的樣本 觀察Premium的樣本的型態 同時將**df_Premium**的樣本和**df**整體進行比較 ```=py filter=df["Coverage"]=="Premium" Premium=df[filter].index df_Premium=df.iloc[Premium] df_Premium #取出Premium的人 ``` ![](https://i.imgur.com/w8ObhMP.png) **(1) 分析性別** 1. 性別分布 ```=py df_Premium["Gender"].value_counts() #發現Premium較多是女生 ``` ![](https://i.imgur.com/0uIN82O.png) 2. **df_Premium**以groupby將性別分群觀察CLV mean的差別 ```=py df_Premium.groupby("Gender").Customer_Lifetime_Value.describe() #發現Premium中女生平均的clv比男生高 #因此建議要多穩固女生客戶 ``` ![](https://i.imgur.com/45EQvzr.png) 3. **df**以groupby將性別分群觀察CLV mean的差別 ```=py df.groupby("Gender").Customer_Lifetime_Value.describe() #回來看看整個群體中以性別分群clv是怎樣的 #可以發現一樣是女生比較高,只是差距沒有那麼明顯 ``` ![](https://i.imgur.com/flxiKBe.png) :::warning :bulb: **發現** 1. df_Premium中女生平均的CLV比男生高 2. df中女生平均的CLV也比男生高,只是沒有Premium差距明顯 3. 是不是可以多穩固女生客戶呢? ::: **(2) 分析教育程度** 1. 教育程度分布 ```=py df_Premium["Education"].value_counts() ``` ![](https://i.imgur.com/jwUS7Kz.png) 本來以為教育程度會較高 結果**高中和高中以下**的占大多數 2. **df_Premium**以groupby將教育程度分群觀察CLV mean的差別 ```=py df_Premium.groupby("Education").Customer_Lifetime_Value.describe() #發現博士的clv最高 ``` ![](https://i.imgur.com/2v6yXgU.png) 3. **df**以groupby將教育程度分群觀察CLV mean的差別 ```=py df.groupby("Education").Customer_Lifetime_Value.describe() #在大群體中反而是碩士clv最高 ``` ![](https://i.imgur.com/3szw1l4.png) :::warning :bulb: **發現** 1. df_Premium中博士的CLV最高 2. df中反而是碩士的CLV最高 ::: **(3) 分析工作狀態** 1. 工作狀態分布 ```=py df_Premium["EmploymentStatus"].value_counts() ``` ![](https://i.imgur.com/tLScG97.png) 發現大家大都是有工作的 2. **df_Premium**以groupby將工作狀態分群觀察CLV mean的差別 ```=py df_Premium.groupby("EmploymentStatus").Customer_Lifetime_Value.describe() #有工作的CLV比較高 #disabled的CLV竟然也蠻高的 ``` ![](https://i.imgur.com/jVvqGQX.png) 3. **df**以groupby將工作狀態分群觀察CLV mean的差別 ```=py df.groupby("EmploymentStatus").Customer_Lifetime_Value.describe() #有收入的人的確clv比較高-->合理 #有趣的是Disabled的人clv也算高 #Retired的人clv最低,最沒價值 ``` ![](https://i.imgur.com/GJTXSCS.png) Disabled的人CLV也算高 :::warning :bulb: **發現** 1. 不管是在df_Premium還是df中有收入的人CLV都較高$\rightarrow$合理 2. 有趣的是disable的人雖然最低薪,但是在兩個群體中都有較高的CLV$\rightarrow$推測失能的人較需要保險的需求 3. <font color="#f00">得出結論:更加強化insight3的看法,應該著重投入拓展disable市場</font> ::: ### Step 6 視覺化檢驗-中介效果檢驗 <font color="#f00">目的</font>$\rightarrow$為了更瞭解變數間的線性關係 **(1) 導入autoviz.AutoViz_Class套件** ```=py from autoviz.AutoViz_Class import AutoViz_Class Vis=AutoViz_Class() ``` **(2) 將df匯出成CSV檔案** ```=py df.to_csv("df.csv") ``` **(3) 將df視覺化處理** ```=py Vis_2=Vis.AutoViz("df.csv") ``` 發現兩張圖有線性關係的展現 1. 總賠償金額-每月自動轉換保費 ![](https://i.imgur.com/AESClsO.png) 2. 每月自動轉換保費-顧客終身價值 ![](https://i.imgur.com/gNCwgvx.png) :::info :information_source: **想法 5** 1. 提出假設:想了解每月自動轉換保費是否會在總賠償金額和顧客終身價值間具有中介效果 ::: **(4) 中介效果驗證** 運用「四步驟法」依序檢驗變數間的關係, 中介效果要滿足以下條件: 1. X→M、M→Y、X→Y這三者的效果都要顯著 2. 「同時」以X, M來預測Y時,X對Y的效果不顯著,但M對Y的效果仍然顯著(X,M→Y) 這樣則表示X和M在效果上有很高的重疊性,且效果是以M為主 **檢驗變數:** X=總賠償金額(Total_Claim_Amount) M=每月自動轉換保費(Monthly_Premium_Auto) Y=顧客終身價值("Customer_Lifetime_Value) **檢驗過程:** 1. X→M ```=py y=df_z["Monthly_Premium_Auto"] x=df_z["Total_Claim_Amount"] model = ols("y ~ x", data=df_z).fit() print(model.summary()) ``` ![](https://i.imgur.com/xPUzOoz.png) p-value<0.05,條件一成立 2. M→Y ```=py y=df_z["Customer_Lifetime_Value"] m=df_z["Monthly_Premium_Auto"] model = ols("y ~ x", data=df_z).fit() print(model.summary()) ``` ![](https://i.imgur.com/8OHCEyS.png) p-value<0.05,條件二成立 3. X→Y ```=py y=df_z["Customer_Lifetime_Value"] x=df_z["Total_Claim_Amount"] model = ols("y ~ x", data=df_z).fit() print(model.summary()) ``` ![](https://i.imgur.com/LrbCXHg.png) p-value<0.05,條件三成立 4. X,M→Y ```=py y=df_z["Customer_Lifetime_Value"] x=df_z["Total_Claim_Amount"] m=df_z["Monthly_Premium_Auto"] model = ols("y ~ x+m", data=df_z).fit() print(model.summary()) ``` ![](https://i.imgur.com/YGPIzxK.png) X→Y的顯著性並無削弱,亦即是代表M沒有在X,Y中間扮演中介變數 :::success :bulb: **Insight 6** 1. 每月自動轉換保費並沒有在總賠償金額和顧客終身價值間中介 2. 但是仍證實每月自動轉換保費對顧客終身價值間具有正向效果 3. <font color="#f00">得出結論:因此我們應該要著重投入每月自動轉換保費高的客戶</font> :::