邏輯迴歸:信貸違規預測!

語言: CN / TW / HK

theme: smartblue

公眾號:尤而小屋
作者:Peter
編輯:Peter

大家好,我是Peter~

今天給大家帶來一篇新的kaggle資料建模文章:信貸違約預測

本文是基於一份Lendingclub上面的信貸資料,根據貸款人的歷史資料和貸款資訊,建立一個邏輯迴歸模型來預測借款人是否會償還他們的貸款。

導圖顯示本文的主要工作,其中缺失值處理特徵工程是重點。

匯入庫

```python import numpy as np import pandas as pd

import matplotlib.pyplot as plt import seaborn as sns

import missingno as ms import plotly.express as px import plotly.graph_objs as go import plotly.figure_factory as ff from plotly.subplots import make_subplots import plotly.offline as pyo pyo.init_notebook_mode() sns.set_style('darkgrid')

from sklearn.decomposition import PCA from imblearn.over_sampling import SMOTE from sklearn.model_selection import train_test_split,cross_val_score

from sklearn.ensemble import RandomForestClassifier,AdaBoostClassifier from sklearn.svm import SVC from sklearn.pipeline import Pipeline from sklearn.preprocessing import StandardScaler from sklearn.metrics import f1_score as f1 from sklearn.metrics import confusion_matrix

plt.rc('figure',figsize=(18,9))

import warnings warnings.filterwarnings("ignore") ```

資料基本資訊

資料來自 LendingClub,它是美國一家個人對個人貸款公司,總部位於加利福尼亞州舊金山,號稱是全球最大的個人對個人(p2p)借貸平臺。

檢視資料量、欄位型別等:

缺失值處理

缺失值處理是本次資料處理的一項重要工作。由於存在字元型和數值型的變數,而且這兩種型別下的資料都存在缺失值,所以在分開處理。

缺失值視覺化

In [6]:

```

4、缺失值情況

df.isnull().sum().sort_values(ascending=False) ```

Out[6]:

id 105451 hardship_start_date 105451 member_id 105451 hardship_type 105451 hardship_reason 105451 ... open_acc_6m 0 tot_cur_bal 0 tot_coll_amt 0 acc_now_delinq 0 max_bal_bc 0 Length: 137, dtype: int64

In [7]:

``` ms.bar(df,color="blue")

plt.show() ```

如果取值是1,說明是完整的欄位,沒有缺失值;可以看到還是存在很多欄位有缺失值。

刪除全部缺失欄位

1、部分欄位是全部缺失的,將它們進行刪除:

In [8]:

```

方法1:使用dropna的how引數

data.dropna(axis=1, how='all')

```

In [9]:

```

在這裡我們使用下面的【方法2】

1、檢視每個欄位的缺失值比例

isnull_col_percent = df.isnull().sum(axis=0).sort_values(ascending=False) / float(len(df)) isnull_col_percent ```

Out[9]:

id 1.0 hardship_start_date 1.0 member_id 1.0 hardship_type 1.0 hardship_reason 1.0 ... open_acc_6m 0.0 tot_cur_bal 0.0 tot_coll_amt 0.0 acc_now_delinq 0.0 max_bal_bc 0.0 Length: 137, dtype: float64

In [10]:

isnull_col_percent[:20] # 前20個

Out[10]:

id 1.000000 hardship_start_date 1.000000 member_id 1.000000 hardship_type 1.000000 hardship_reason 1.000000 hardship_status 1.000000 deferral_term 1.000000 hardship_amount 1.000000 hardship_end_date 1.000000 url 1.000000 payment_plan_start_date 1.000000 hardship_length 1.000000 hardship_dpd 1.000000 hardship_loan_status 1.000000 orig_projected_additional_accrued_interest 1.000000 hardship_payoff_balance_amount 1.000000 desc 1.000000 hardship_last_payment_amount 1.000000 sec_app_mths_since_last_major_derog 0.977866 sec_app_revol_util 0.936188 dtype: float64

在上面的結果中,比例為1的欄位就是全部缺失的(前面18個欄位),對於建模無用,我們將其刪除:

In [11]:

no_use_col = df.columns[df.isnull().all()].tolist() no_use_col

Out[11]:

['id', 'member_id', 'url', 'desc', 'hardship_type', 'hardship_reason', 'hardship_status', 'deferral_term', 'hardship_amount', 'hardship_start_date', 'hardship_end_date', 'payment_plan_start_date', 'hardship_length', 'hardship_dpd', 'hardship_loan_status', 'orig_projected_additional_accrued_interest', 'hardship_payoff_balance_amount', 'hardship_last_payment_amount']

In [12]:

df.drop(no_use_col,axis=1,inplace=True)

In [13]:

df.shape # 137-18 = 119,成功刪除18個屬性

Out[13]:

(105451, 119)

刪除缺失值在30%以上的欄位

2、有些欄位是部分缺失值;缺失量過大也會對建模造成影響。

在這裡我們設定刪除缺失值在30%(可以設定其他值)以上的欄位(按照列的方向來統計)

In [14]:

```

最大的缺失值比例高達97.78%

df.isnull().sum(axis=0).sort_values(ascending=False) / float(len(df)) ```

Out[14]:

sec_app_mths_since_last_major_derog 0.977866 sec_app_revol_util 0.936188 revol_bal_joint 0.935458 sec_app_earliest_cr_line 0.935458 sec_app_inq_last_6mths 0.935458 ... total_rec_int 0.000000 total_rec_prncp 0.000000 total_pymnt_inv 0.000000 total_pymnt 0.000000 hardship_flag 0.000000 Length: 119, dtype: float64

In [15]:

``` thresh = len(df)*0.3 # 閥值(缺失值數量)

某列資料缺失的數量超過閥值就被刪除

df.dropna(thresh=thresh, axis=1, inplace=True) ```

In [16]:

df.shape

Out[16]:

(105451, 102)

In [17]:

df.isnull().sum(axis=0).sort_values(ascending=False) / float(len(df))

Out[17]:

mths_since_recent_revol_delinq 0.648405 mths_since_last_delinq 0.484765 il_util 0.126884 mths_since_recent_inq 0.113313 emp_title 0.064314 ... total_pymnt_inv 0.000000 total_pymnt 0.000000 out_prncp_inv 0.000000 out_prncp 0.000000 hardship_flag 0.000000 Length: 102, dtype: float64

新資料(刪除缺失值)

新資料缺失值視覺化

In [18]:

``` ms.bar(df,color="blue")

plt.show() ```

和之前的對比,發現缺失值的欄位少了很多

處理後的資料量:只剩下102個欄位

In [19]:

df.shape

Out[19]:

(105451, 102)

欄位型別統計

In [20]:

df.dtypes.value_counts()

Out[20]:

int64 54 float64 25 object 23 dtype: int64

唯一值欄位

3、某些欄位的取值是唯一的,比如全部是0,這樣的欄位對於建模也是無用的,我們要將這些欄位進行刪除。

首先找出這些欄位:使用Pandas中的nunique函式來確定取值是否唯一。

In [21]:

nunique_data = df.apply(pd.Series.nunique) != 1 # 不唯一的欄位 nunique_data

Out[21]:

loan_amnt True funded_amnt True funded_amnt_inv True term True int_rate True ... tot_hi_cred_lim True total_bal_ex_mort True total_bc_limit True total_il_high_credit_limit True hardship_flag False Length: 102, dtype: bool

In [22]:

```

df1:刪除唯一值欄位後的資料

df1 = df.loc[:, nunique_data] df1.shape ```

Out[22]:

(105451, 97)

欄位從102變成了97,說明還是存在5個取值唯一的欄位

In [23]:

```

再次檢視欄位型別

df1.dtypes.value_counts() ```

Out[23]:

int64 51 float64 25 object 21 dtype: int64

缺失值處理-分型別變數

針對分型別變數(取值為字串型別)的缺失值處理,一般是採用型別編碼、獨熱碼、因子化等操作

In [24]:

object_df = df1.select_dtypes(include="object") object_df.columns

Out[24]:

Index(['term', 'int_rate', 'grade', 'sub_grade', 'emp_title', 'emp_length', 'home_ownership', 'verification_status', 'issue_d', 'loan_status', 'purpose', 'title', 'zip_code', 'addr_state', 'earliest_cr_line', 'revol_util', 'initial_list_status', 'last_pymnt_d', 'next_pymnt_d', 'last_credit_pull_d', 'application_type'], dtype='object')

比如欄位grade的取值是真實的Object型別:

In [25]:

```

grade

df1["grade"].value_counts() ```

Out[25]:

C 36880 B 31301 A 17898 D 12015 E 4847 F 1725 G 785 Name: grade, dtype: int64

下面出現的欄位雖然是object型別,但是實際上行它們的取值仍存在一定的大小關係

In [26]:

```

int_rate

df1["int_rate"].value_counts() ```

Out[26]:

16.02% 4956 5.32% 4365 15.05% 4195 14.08% 4168 12.74% 4155 ... 30.75% 119 30.49% 113 30.74% 98 21.49% 89 6.00% 4 Name: int_rate, Length: 65, dtype: int64

In [27]:

```

revol_util

df1["revol_util"].value_counts() ```

Out[27]:

0% 468 60% 244 64% 230 50% 227 53% 220 ... 116.20% 1 110.10% 1 106.10% 1 125% 1 113% 1 Name: revol_util, Length: 1076, dtype: int64

分型別變數轉成數值

  1. 將百分比的資料轉成浮點型:

In [28]:

```

將右側的%去掉,同時強制轉成float型別

df1["int_rate"] = df1["int_rate"].str.rstrip("%").astype("float") df1["revol_util"] = df1["revol_util"].str.rstrip("%").astype("float") ```

  1. 關於年份的處理:轉成數值,並且10+直接用10代替,<1的部分直接用0代替:

In [29]:

```

emp_length

df1["emp_length"].value_counts() ```

Out[29]:

10+ years 35438 2 years 9914 < 1 year 9542 3 years 8495 1 year 7034 4 years 6453 5 years 6382 6 years 4526 7 years 3847 9 years 3828 8 years 3295 Name: emp_length, dtype: int64

In [30]:

df1["emp_length"].isnull().sum() # 存在缺失值

Out[30]:

6697

現將缺失值填充為<1 year

In [31]:

df1["emp_length"] = df1["emp_length"].fillna("< 1 year")

In [32]:

```

1、先將year或years去掉

df1["emp_length"] = df1["emp_length"].apply(lambda x: x.split("y")[0].rstrip(" ")) ```

In [33]:

df1["emp_length"].value_counts()

Out[33]:

10+ 35438 < 1 16239 2 9914 3 8495 1 7034 4 6453 5 6382 6 4526 7 3847 9 3828 8 3295 Name: emp_length, dtype: int64

In [34]:

```

2、轉成數值型

df1["emp_length"] = df1["emp_length"].apply(lambda x: "10" if x == "10+" else x) df1["emp_length"] = df1["emp_length"].str.replace("< 1","0")

df1["emp_length"] = df1["emp_length"].astype("float") ```

In [35]:

df1["emp_length"].value_counts()

Out[35]:

python 10.0 35438 0.0 16239 2.0 9914 3.0 8495 1.0 7034 4.0 6453 5.0 6382 6.0 4526 7.0 3847 9.0 3828 8.0 3295 Name: emp_length, dtype: int64

分型別變數視覺化

In [36]:

object_df = df1.select_dtypes(include="object") object_df.columns

Out[36]:

Index(['term', 'grade', 'sub_grade', 'emp_title', 'home_ownership', 'verification_status', 'issue_d', 'loan_status', 'purpose', 'title', 'zip_code', 'addr_state', 'earliest_cr_line', 'initial_list_status', 'last_pymnt_d', 'next_pymnt_d', 'last_credit_pull_d', 'application_type'], dtype='object')

In [37]:

``` ms.matrix(object_df)

plt.show() ```

主要是兩個欄位缺失值:emp_title、next_pymnt_d

缺失值填充

In [38]:

object_df.isnull().sum()

Out[38]:

term 0 grade 0 sub_grade 0 emp_title 6782 home_ownership 0 verification_status 0 issue_d 0 loan_status 0 purpose 0 title 0 zip_code 0 addr_state 0 earliest_cr_line 0 initial_list_status 0 last_pymnt_d 145 next_pymnt_d 3921 last_credit_pull_d 3 application_type 0 dtype: int64

在這裡我們直接填充為“Unknown”:

In [39]:

object_df.fillna("Unknown",inplace=True)

再次檢視發現已經沒有缺失值:

In [40]:

缺失值處理——數值型變數

In [41]:

number_df = df1.select_dtypes(exclude="object") number_df.columns

Out[41]:

Index(['loan_amnt', 'funded_amnt', 'funded_amnt_inv', 'int_rate', 'installment', 'emp_length', 'annual_inc', 'dti', 'delinq_2yrs', 'inq_last_6mths', 'mths_since_last_delinq', 'open_acc', 'pub_rec', 'revol_bal', 'revol_util', 'total_acc', 'out_prncp', 'out_prncp_inv', 'total_pymnt', 'total_pymnt_inv', 'total_rec_prncp', 'total_rec_int', 'total_rec_late_fee', 'last_pymnt_amnt', 'collections_12_mths_ex_med', 'acc_now_delinq', 'tot_coll_amt', 'tot_cur_bal', 'open_acc_6m', 'open_il_6m', 'open_il_12m', 'open_il_24m', 'mths_since_rcnt_il', 'total_bal_il', 'il_util', 'open_rv_12m', 'open_rv_24m', 'max_bal_bc', 'all_util', 'total_rev_hi_lim', 'inq_fi', 'total_cu_tl', 'inq_last_12m', 'acc_open_past_24mths', 'avg_cur_bal', 'bc_open_to_buy', 'bc_util', 'chargeoff_within_12_mths', 'delinq_amnt', 'mo_sin_old_il_acct', 'mo_sin_old_rev_tl_op', 'mo_sin_rcnt_rev_tl_op', 'mo_sin_rcnt_tl', 'mort_acc', 'mths_since_recent_bc', 'mths_since_recent_inq', 'mths_since_recent_revol_delinq', 'num_accts_ever_120_pd', 'num_actv_bc_tl', 'num_actv_rev_tl', 'num_bc_sats', 'num_bc_tl', 'num_il_tl', 'num_op_rev_tl', 'num_rev_accts', 'num_rev_tl_bal_gt_0', 'num_sats', 'num_tl_120dpd_2m', 'num_tl_30dpd', 'num_tl_90g_dpd_24m', 'num_tl_op_past_12m', 'pct_tl_nvr_dlq', 'percent_bc_gt_75', 'pub_rec_bankruptcies', 'tax_liens', 'tot_hi_cred_lim', 'total_bal_ex_mort', 'total_bc_limit', 'total_il_high_credit_limit'], dtype='object')

In [42]:

number_df.shape

Out[42]:

(105451, 79)

缺失值視覺化

In [43]:

ms.matrix(number_df) plt.show()

如何判斷某行是否全部為空

檢視缺失值情況

In [48]:

number_df.isnull().sum().sort_values(ascending=False)

Out[48]:

mths_since_recent_revol_delinq 68375 mths_since_last_delinq 51119 il_util 13380 mths_since_recent_inq 11949 num_tl_120dpd_2m 5278 ... tot_cur_bal 0 tot_coll_amt 0 acc_now_delinq 0 collections_12_mths_ex_med 0 total_il_high_credit_limit 0 Length: 79, dtype: int64

找出存在缺失值的欄位

In [49]:

```

存在缺失值的為True,否則為False

number_df.isnull().sum() > 0 ```

Out[49]:

loan_amnt False funded_amnt False funded_amnt_inv False int_rate False installment False ... tax_liens False tot_hi_cred_lim False total_bal_ex_mort False total_bc_limit False total_il_high_credit_limit False Length: 79, dtype: bool

In [50]:

number_df.columns[number_df.isnull().sum() > 0]

Out[50]:

Index(['dti', 'mths_since_last_delinq', 'revol_util', 'mths_since_rcnt_il', 'il_util', 'all_util', 'avg_cur_bal', 'bc_open_to_buy', 'bc_util', 'mo_sin_old_il_acct', 'mths_since_recent_bc', 'mths_since_recent_inq', 'mths_since_recent_revol_delinq', 'num_tl_120dpd_2m', 'percent_bc_gt_75'], dtype='object')

缺失值填充

對於數值型變數的缺失值,我們採用每列的均值來填充

In [51]:

```

方法1

for col in number_df.columns[number_df.isnull().sum() > 0]: mean_val = number_df[col].mean() # 每列的均值 number_df[col].fillna(mean_val, inplace=True) # 均值填充 ```

In [52]:

```

方法2

老版本報錯

from sklearn.preprocessing import Imputer

使用新版本

from sklearn.impute import SimpleImputer imputer = SimpleImputer(missing_values=np.nan, strategy='mean') ```

In [53]:

number_df.isnull().sum().sort_values(ascending=False)

Out[53]:

python loan_amnt 0 mo_sin_old_rev_tl_op 0 num_accts_ever_120_pd 0 mths_since_recent_revol_delinq 0 mths_since_recent_inq 0 .. acc_now_delinq 0 collections_12_mths_ex_med 0 last_pymnt_amnt 0 total_rec_late_fee 0 total_il_high_credit_limit 0 Length: 79, dtype: int64

新建模資料new_data

手動過濾欄位

有些欄位對建模是無用的,即存在冗餘的欄位資訊,我們需要手動刪除。

In [54]:

object_df.isnull().sum()

Out[54]:

term 0 grade 0 sub_grade 0 emp_title 0 home_ownership 0 verification_status 0 issue_d 0 loan_status 0 purpose 0 title 0 zip_code 0 addr_state 0 earliest_cr_line 0 initial_list_status 0 last_pymnt_d 0 next_pymnt_d 0 last_credit_pull_d 0 application_type 0 dtype: int64

In [55]:

object_df["application_type"].value_counts()

Out[55]:

INDIVIDUAL 98619 JOINT 6813 DIRECT_PAY 19 Name: application_type, dtype: int64

  • term:申請人的貸款償還期數,通常是36或者60,對於建模沒有指導意義,保留(1)
  • grade和sub_grade:存在重複資訊,選擇刪除欄位sub_gracde,保留grade(12)
  • emp_title:不能反映借款人的收入或者資產情況,可刪除
  • home_ownership:房屋所在狀態,保留(3)
  • verification_status:收入是否被LC驗證、未驗證或收入來源是否被驗證,保留(4)
  • issue_d:貸款發行時間,對於是否違規預測也沒有指導意義,可刪除
  • loan_status:貸款的當前狀態,保留(5)
  • purpose:貸款目的,保留(6)
  • title:和purpose重複,可刪除
  • zip_code:地址郵編,對於建模無效
  • addr_state:申請人的地址所在州,建模無效
  • earliest_cr_line:借款人最早公佈的信用額度開通的月份,對於是否違規模型搭建無意義,考慮刪除
  • initial_list_status:貸款的初始上市狀態,可謂W或者F,保留(7)
  • last_pymnt_d、next_pymnt_d、last_credit_pull_d:貸款後的資訊,對於是否違規預測為意義,可刪除
  • application_type:指示貸款是單獨申請還是與兩個共同借款人的聯合申請,保留(8)

最終留下8個有用的欄位資訊:

In [56]:

``` object_df = object_df[["term","grade","home_ownership","verification_status","loan_status", "purpose","initial_list_status","application_type"]]

object_df ```

資料合併

將兩個資料合併起來:

In [57]:

new_data = pd.concat([object_df,number_df],axis=1) new_data.head()

基本資訊

In [58]:

new_data.dtypes

Out[58]:

term object grade object home_ownership object verification_status object loan_status object ... tax_liens int64 tot_hi_cred_lim int64 total_bal_ex_mort int64 total_bc_limit int64 total_il_high_credit_limit int64 Length: 87, dtype: object

In [59]:

new_data.shape

Out[59]:

(105451, 87)

描述統計資訊

針對數值型欄位的描述統計資訊,檢視最值,四分位數等:

In [60]:

new_data.describe()

特徵工程

特徵衍生

In [61]:

installment / (annual_inc / 12):表示每個月的還款金額佔據月收入的比例,數值越大,還款壓力越大

```python

installment:每月的還款金額

annual_inc:申請人年度總收入

新特徵

new_data["installment_percent"] = new_data[["installment","annual_inc"]].apply(lambda x: x.installment / (x.annual_inc / 12), axis=1).replace([np.inf,0]) new_data.head() ```

Out[61]:

貸款狀態編碼與視覺化

編碼

In [62]:

new_data["loan_status"].value_counts()

Out[62]:

Current 99850 Fully Paid 3896 In Grace Period 932 Late (31-120 days) 436 Late (16-30 days) 312 Charged Off 25 Name: loan_status, dtype: int64

In [63]:

```

違約=1, 正常=0

new_data["loan_status"] = new_data["loan_status"].apply(lambda x: 0 if (x == "Fully Paid" or x == "Current") else 1) ```

In [64]:

new_data["loan_status"].value_counts()

Out[64]:

0 103746 1 1705 Name: loan_status, dtype: int64

視覺化

In [65]:

```python

貸款狀態柱狀圖統計

fig, axs = plt.subplots(1,2,figsize=(12,6)) sns.countplot(x='loan_status', data=new_data, ax=axs[0])

axs[0].set_title("Frequency of each Loan Status(Bar)")

餅圖:統計每個型別的佔比

new_data['loan_status'].value_counts().plot(x=None, y=None, kind='pie', ax=axs[1], autopct='%1.2f%%') axs[1].set_title("Percentage of each Loan status(Pie)") plt.show() ```

可以看到違規和沒有違規的比例差別是很大的,後面會通過取樣的方法來解決。

有序變數編碼

部分欄位的取值是存在一定的順序關係。比如服裝的尺碼大小,"XS"、"S"、"M"、"L"等,它們的取值本身是有大小關係的。

在這裡我們實施硬編碼:

In [66]:

new_data.select_dtypes("object")

無序特徵編碼

採用的獨熱碼,通過get_dummies函式來實現

In [68]:

df1 = new_data.select_dtypes("object") # 字元型 df2 = new_data.select_dtypes(exclude=["object"]) # 非字元型 df1.head()

Out[68]:

特徵縮放:標準化

針對數值型特徵(資料df2)的特徵縮放,將資料規範到一定範圍內,便於後期加快演算法的收斂速度

In [70]:

```

目標變數load_status

Y = df2[["loan_status"]] Y.head() ```

Out[70]:

| | loan_status | | ---: | ----------: | | 0 | 0 | | 1 | 0 | | 2 | 0 | | 3 | 0 | | 4 | 0 |

In [71]:

```

df2中剩餘的數值型變數構成df3

df3 = df2.drop("loan_status",axis=1) df3.head() ```

```python

對df3實施標準化處理

from sklearn.preprocessing import StandardScaler ss = StandardScaler() ss_data = ss.fit_transform(df3)

df4 = pd.DataFrame(ss_data, columns=df3.columns) df4.head() ```

SMOTE取樣(重點)

可以看到違規和沒有違規的比例差別是很大的,也就是說樣本及其不均衡,常用的處理方式有兩種:

  • 過取樣(oversampling),增加正樣本使得正、負樣本數目接近,然後再進行學習
  • 欠取樣(undersampling),去除一些負樣本使得正、負樣本數目接近,然後再進行學習。

下面通過欠取樣方法來處理:

In [75]:

positive_data = new_df[new_df["loan_status"] == 1] # 違約 negetive_data = new_df[new_df["loan_status"] == 0] # 未違約

In [76]:

print("length of positive_data: ",len(positive_data)) print("length of negetive_data: ",len(negetive_data)) length of positive_data: 1705 length of negetive_data: 103746

In [77]:

``` selected_data = negetive_data.sample(len(positive_data))

selected_data.shape ```

Out[77]:

(1705, 104)

下面生成的new_data就是最終用於建模的資料:

In [78]:

new_data = pd.concat([positive_data,selected_data],axis=0) new_data

建模

特徵和目標分離

In [79]:

y = new_data[["loan_status"]] X = new_data.drop("loan_status", axis=1)

訓練集和測試集切分

In [80]:

from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=4)

邏輯迴歸分類器

基於邏輯迴歸的分類器

In [81]:

``` from sklearn.linear_model import LogisticRegression clf = LogisticRegression() # 構建邏輯迴歸分類器

clf.fit(X_train, y_train) ```

Out[81]:

LogisticRegression()

In [82]:

```

進行預測

predict = clf.predict(X_test) predict[:5] ```

Out[82]:

array([1, 1, 0, 1, 1])

預測準確率

檢視預測的準確率:

In [83]:

``` from sklearn.metrics import accuracy_score

accuracy_score(predict, y_test) ```

Out[83]:

0.7067448680351907

混淆矩陣的資訊:

In [84]:

from sklearn.metrics import confusion_matrix m = confusion_matrix(y_test, predict) m

Out[84]:

array([[262, 87], [113, 220]])

In [85]:

```

混淆矩陣視覺化

plt.figure(figsize=(12,8)) sns.heatmap(m)

plt.show() ```

上面視覺化的結果表示:顏色越深代表的人數越多,也就是真陽性的人數是最多的;而假陽性是最少的

roc曲線

In [86]:

``` from sklearn.metrics import roc_curve, auc false_positive_rate, true_positive_rate,thresholds = roc_curve(y_test, predict)

roc_auc = auc(false_positive_rate,true_positive_rate) roc_auc ```

Out[86]:

0.7056884965194421

In [87]:

``` import matplotlib.pyplot as plt plt.figure(figsize=(10,10)) plt.title("ROC") # Receiver Operating Characteristic plt.plot(false_positive_rate, true_positive_rate, color="red", label="AUC = %0.2f"%roc_auc )

plt.legend(loc="lower right") plt.plot([0,1],[0,1],linestyle="--") plt.axis("tight")

真陽性:預測類別為1的positive;預測正確True

plt.ylabel("True Positive Rate")

假陽性:預測類別為1的positive;預測錯誤False

plt.xlabel("False Positive Rate") ```

Out[87]:

Text(0.5, 0, 'False Positive Rate')

總結

整體方案的ROC值達到了71%,還是有一定的提升空間。後續可以優化的點:

  1. 特徵屬性過多:可以考慮降維或者特徵的多重線性檢驗,找出更具有價值的特徵
  2. 離散型變數的編碼:目前是統一的標準化處理,沒有編碼工作;後續可以考慮加入編碼工作,比如:因子化、特徵分箱等
  3. 建模優化:嘗試使用不同的分類模型,以及模型融合方法
  4. 引數調優:可以考慮做一個引數的調優,比如網格搜尋、隨機搜尋等等