一、項(xiàng)目介紹
.
Loan Prediction 數(shù)據(jù)集是保險(xiǎn)領(lǐng)域最常引用的一個(gè)數(shù)據(jù)集。利用這個(gè)數(shù)據(jù)集修然,你可以充分體驗(yàn)到如何處理保險(xiǎn)公司的數(shù)據(jù),包括會(huì)遇到哪些挑戰(zhàn)、需要什么策略愕宋、哪些變量會(huì)影響結(jié)果等玻靡。這是一個(gè)分類問題,數(shù)據(jù)集包含614行13列個(gè)數(shù)據(jù)中贝。
問題:
預(yù)測一個(gè)貸款是否能夠被批準(zhǔn)囤捻。
資源:
分析環(huán)境:
- Python3
- jupyter notebook
二、使用Python pandas庫對(duì)數(shù)據(jù)集進(jìn)行探索性分析
.
導(dǎo)入庫和數(shù)據(jù)集
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
df = pd.read_csv('loan_train.csv')
df.head()
快速數(shù)據(jù)探索
變量的描述:
- Loan_ID: 貸款人ID
- Gender: 性別 (Male, female)
- ApplicantIncome: 申請(qǐng)人收入
- Coapplicant Income: 申請(qǐng)收入
- Credit_History: 信用記錄
- Dependents: 親屬人數(shù)
- Education: 教育程度
- LoanAmount: 貸款額度
- Loan_Amount_Term: 貸款時(shí)間長
- Loan_Status: 貸款狀態(tài) (Y, N)
- Married: 婚姻狀況(NO,Yes)
- Property_Area: 所在區(qū)域包括:城市地區(qū)邻寿、半城區(qū)和農(nóng)村地區(qū)
描述統(tǒng)計(jì):
df.describe()
根據(jù)描述統(tǒng)計(jì)數(shù)據(jù)蝎土,我們可以得出一些結(jié)論:
- 我們可以得出一些數(shù)據(jù)項(xiàng)的缺失值(比如:LoanAmount (614 – 592) 22個(gè)缺失值)。
- 我們還可以看到大約84%的申請(qǐng)人擁有credit_history绣否。Credit_History字段的平均值為0.84(對(duì)于有信用記錄的人誊涯,Credit_History的值為1,否則為0)
- ApplicantIncome分布似乎符合期望枝秤, CoapplicantIncome也一樣醋拧。
分布分析
現(xiàn)在我們熟悉基本數(shù)據(jù)特征,讓我們研究各種變量的分布淀弹。 讓我們從數(shù)字變量開始 - 即ApplicantIncome和LoanAmount丹壕。
首先繪制ApplicantIncome的直方圖:
df['ApplicantIncome'].hist(bins=50)
在這里,我們觀察到極少數(shù)極值薇溃。接下來菌赖,我們查看箱形圖以了解分布。
這證實(shí)了存在許多異常值/極值沐序。 這可歸因于社會(huì)的收入差距琉用。 部分原因可能是我們正在關(guān)注具有不同教育水平的人。 讓我們通過教育將它們分開:
df.boxplot(column='ApplicantIncome', by = 'Education')
我們可以看到策幼,畢業(yè)生和非畢業(yè)生的平均收入之間沒有實(shí)質(zhì)性的差異邑时。 但是有更多的高收入畢業(yè)生,這似乎是異常值特姐。
現(xiàn)在晶丘,讓我們查看LoanAmount的直方圖和boxplot:
df['LoanAmount'].hist(bins=50)
df.boxplot(column='LoanAmount')
同樣,有一些極端的價(jià)值觀唐含。 顯然浅浮,ApplicantIncome和LoanAmount都需要一些數(shù)據(jù)量。 LoanAmount缺少并且具有極值捷枯,而ApplicantIncome有一些極端值滚秩,需要更深入的理解递惋。 我們將在接下來的部分中討論這個(gè)問題坑匠。
分類變量分析
現(xiàn)在我們了解了ApplicantIncome和LoanIncome的分布,讓我們更詳細(xì)地了解分類變量惊来。
使用Python生成數(shù)據(jù)透視表:
temp1 = df['Credit_History'].value_counts(ascending=True)
temp2 = df.pivot_table(values='Loan_Status',index=['Credit_History'],aggfunc=lambda x: x.map({'Y':1,'N':0}).mean())
print ('Frequency Table for Credit History:')
print (temp1)
print ('\nProbility of getting loan for each Credit History class:')
print (temp2)
結(jié)果:
Frequency Table for Credit History:
0.0 89
1.0 475
Name: Credit_History, dtype: int64
Probility of getting loan for each Credit History class:
Loan_Status
Credit_History
0.0 0.078652
1.0 0.795789
現(xiàn)在我們可以觀察到我們得到了類似于MS Excel的pivot_table。 可以使用“matplotlib”庫將其繪制為條形圖:
import matplotlib.pyplot as plt
fig = plt.figure(figsize=(8,4))
ax1 = fig.add_subplot(121)
ax1.set_xlabel('Credit_History')
ax1.set_ylabel('Count of Applicants')
ax1.set_title("Applicants by Credit_History")
temp1.plot(kind='bar')
ax2 = fig.add_subplot(122)
#temp2.plot(kind = 'bar')
plt.bar(temp2.index, temp2['Loan_Status'])
ax2.set_xlabel('Credit_History')
ax2.set_ylabel('Probability of getting loan')
ax2.set_title("Probability of getting loan by credit history")
這表明已艰,如果申請(qǐng)人有有效的信用記錄痊末,獲得貸款的機(jī)會(huì)是八倍。 您可以通過Married哩掺,Self-Employed凿叠,Property_Area等繪制類似的圖表。
或者嚼吞,這兩個(gè)圖也可以通過在堆疊圖表中組合來可視化:
1.Credut_History:
temp3 = pd.crosstab(df['Credit_History'], df['Loan_Status'])
temp3.plot(kind='bar', stacked=True, color=['red','blue'], grid=False)
2.Married
Married=pd.crosstab(df['Married'],df['Loan_Status'])
Married.plot(kind="bar", stacked=True)
已結(jié)婚客戶更容易獲得貸款
3.Self-Employed
Self_Employed=pd.crosstab(df['Self_Employed'],df['Loan_Status'])
Self_Employed.plot(kind="bar", stacked=True)
非self_employed更容易獲得貸款.
4.Property_Area
Property_Area=pd.crosstab(df['Property_Area'],df['Loan_Status'])
Property_Area.plot(kind="bar", stacked=True)
在半城市區(qū)獲得批準(zhǔn)的貸款要高于農(nóng)村或城市地區(qū).
如果你還沒有意識(shí)到盒件,我們剛剛在這里創(chuàng)建了兩個(gè)基本的分類算法,一個(gè)基于信用歷史舱禽,另一個(gè)基于2個(gè)分類變量(包括性別).我們剛剛學(xué)習(xí)了如何使用Pandas在Python中進(jìn)行探索性分析炒刁。接下來讓我們進(jìn)一步探索ApplicantIncome和LoanStatus變量,執(zhí)行數(shù)據(jù)修改并創(chuàng)建數(shù)據(jù)集以應(yīng)用各種建模技術(shù)誊稚。
三翔始、缺失值和異常值處理
.
在我們對(duì)數(shù)據(jù)進(jìn)行探索的過程中,我們發(fā)現(xiàn)數(shù)據(jù)集中存在一些問題里伯,需要在數(shù)據(jù)為良好模型做好準(zhǔn)備之前解決城瞎。此練習(xí)通常稱為“Data Munging”。以下是我們已經(jīng)知道的問題:
- 某些變量中缺少值疾瓮。我們應(yīng)該根據(jù)缺失值的數(shù)量和變量的預(yù)期重要性來明智地估計(jì)這些值脖镀。
- 在查看分布時(shí),我們看到ApplicantIncome和LoanAmount似乎在兩端都包含極值狼电。雖然它們可能具有直觀意義蜒灰,但應(yīng)該得到恰當(dāng)?shù)膶?duì)待。
除了數(shù)字字段的這些問題之外肩碟,我們還應(yīng)該查看非數(shù)字字段强窖,例如Gender,Property_Area削祈,Married翅溺,Education和Dependents,看它們是否包含任何有用的信息岩瘦。
缺失值處理
df.isnull().sum()
結(jié)果:
Loan_ID 0
Gender 13
Married 3
Dependents 15
Education 0
Self_Employed 32
ApplicantIncome 0
CoapplicantIncome 0
LoanAmount 22
Loan_Amount_Term 14
Credit_History 50
Property_Area 0
Loan_Status 0
dtype: int64
盡管缺失值的數(shù)量不是很多,但是許多變量都有它們窿撬,并且應(yīng)該估算這些值中的每一個(gè)并將其添加到數(shù)據(jù)中启昧。此處填充缺失值的方法:
- 對(duì)于數(shù)值變量:使用均值或中位數(shù)進(jìn)行插補(bǔ)。
- 對(duì)于分類變量:使用常見眾數(shù)進(jìn)行插補(bǔ)劈伴,這里主要使用眾數(shù)進(jìn)行插補(bǔ)空值密末。
如下:
df['Gender'].fillna(df['Gender'].value_counts().idxmax(), inplace=True)
df['Married'].fillna(df['Married'].value_counts().idxmax(), inplace=True)
df['Dependents'].fillna(df['Dependents'].value_counts().idxmax(), inplace=True)
df['Self_Employed'].fillna(df['Self_Employed'].value_counts().idxmax(), inplace=True)
df["LoanAmount"].fillna(df["LoanAmount"].mean(skipna=True), inplace=True)
df['Loan_Amount_Term'].fillna(df['Loan_Amount_Term'].value_counts().idxmax(), inplace=True)
df['Credit_History'].fillna(df['Credit_History'].value_counts().idxmax(), inplace=True)
查看是否存在缺失值:
df.info()
結(jié)果:
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 614 entries, 0 to 613
Data columns (total 13 columns):
Loan_ID 614 non-null object
Gender 614 non-null object
Married 614 non-null object
Dependents 614 non-null object
Education 614 non-null object
Self_Employed 614 non-null object
ApplicantIncome 614 non-null int64
CoapplicantIncome 614 non-null float64
LoanAmount 614 non-null float64
Loan_Amount_Term 614 non-null float64
Credit_History 614 non-null float64
Property_Area 614 non-null object
Loan_Status 614 non-null object
dtypes: float64(4), int64(1), object(8)
memory usage: 62.4+ KB
可以看到數(shù)據(jù)集中已填充所有缺失值握爷,沒有缺失值存在。
異常值處理
讓我們先分析一下LoanAmount严里。 由于極端值實(shí)際上是可能的新啼,即某些人可能因特定需求而申請(qǐng)高價(jià)值貸款。 因此刹碾,不要將它們視為異常值燥撞,而是嘗試進(jìn)行l(wèi)og轉(zhuǎn)換以消除它們的影響:
df['LoanAmount_log'] = np.log(df['LoanAmount'])
df['LoanAmount_log'].hist(bins=20)
現(xiàn)在分布看起來更接近正常,極端值的影響已經(jīng)顯著消退迷帜。
來到申請(qǐng)人收入物舒。 一種直覺可能是一些申請(qǐng)人的收入較低但是對(duì)申請(qǐng)人的支持很強(qiáng)。 因此戏锹,將兩種收入合并為總收入并對(duì)其進(jìn)行對(duì)數(shù)轉(zhuǎn)換可能是一個(gè)好主意冠胯。
df['TotalIncome'] = df['ApplicantIncome'] + df['CoapplicantIncome']
df['TotalIncome_log'] = np.log(df['TotalIncome'])
df['LoanAmount_log'].hist(bins=20)
四、建立預(yù)測模型
.
因?yàn)閟klearn要求所有輸入都是數(shù)字锦针,我們應(yīng)該通過編碼類別將所有分類變量轉(zhuǎn)換為數(shù)字荠察。
from sklearn.preprocessing import LabelEncoder
var_mod = ['Gender','Married','Dependents','Education','Self_Employed','Property_Area','Loan_Status']
le = LabelEncoder()
for i in var_mod:
df[i] = le.fit_transform(df[i])
df.dtypes
接下來,我們將導(dǎo)入所需的模塊奈搜。 然后我們將定義一個(gè)通用的分類函數(shù)悉盆,它將模型作為輸入并確定準(zhǔn)確度和交叉驗(yàn)證分?jǐn)?shù)。
# 導(dǎo)入相關(guān)模塊
from sklearn.linear_model import LogisticRegression
from sklearn.cross_validation import KFold #For K-fold cross validation
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier, export_graphviz
from sklearn import metrics
# 用于制作分類模型和訪問性能的通用函數(shù):
def classification_model(model, data, predictors, outcome):
# 訓(xùn)練模型
model.fit(data[predictors],data[outcome])
#測試數(shù)據(jù)
predictions = model.predict(data[predictors])
# 打印精度
accuracy = metrics.accuracy_score(predictions,data[outcome])
print ("Accuracy : %s" % "{0:.3%}".format(accuracy))
# 用5倍進(jìn)行k倍交叉驗(yàn)證
kf = KFold(data.shape[0], n_folds=5)
error = []
for train, test in kf:
# 過濾測試數(shù)據(jù)
train_predictors = (data[predictors].iloc[train,:])
# 我們用來訓(xùn)練算法的目標(biāo)媚污。
train_target = data[outcome].iloc[train]
# 使用預(yù)測變量和目標(biāo)訓(xùn)練算法舀瓢。
model.fit(train_predictors, train_target)
# 記錄每次交叉驗(yàn)證運(yùn)行的錯(cuò)誤
error.append(model.score(data[predictors].iloc[test,:], data[outcome].iloc[test]))
print ("Cross-Validation Score : %s" % "{0:.3%}".format(np.mean(error)))
#Fit the model again so that it can be refered outside the function:
model.fit(data[predictors],data[outcome])
邏輯回歸
把所有變量進(jìn)入模型,但這可能導(dǎo)致過度擬合。我們可以很容易的做一些直觀的假設(shè)再開始進(jìn)入模型耗美。 獲得貸款的可能性會(huì)更高的因素:
- 申請(qǐng)人有一個(gè)好的信用記錄
- 高收入申請(qǐng)人
- 更高的教育水平
- 區(qū)域在城市和半城市
第一個(gè)模型與“Credit_History”
outcome_var = 'Loan_Status'
model = LogisticRegression()
predictor_var = ['Credit_History']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:80.945%交叉驗(yàn)證得分:80.946%
我們可以嘗試不同的組合的變量:
predictor_var = ['Credit_History','Education','Married','Self_Employed','Property_Area']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:80.945%交叉驗(yàn)證得分:80.946%
通常我們期望在添加變量時(shí)增加準(zhǔn)確性京髓。 但這是一個(gè)更具挑戰(zhàn)性的案例。 準(zhǔn)確性和交叉驗(yàn)證得分不會(huì)受到不太重要的變量的影響商架。 Credit_History占主導(dǎo)地位堰怨。 我們現(xiàn)在有兩個(gè)選擇:
- 特征工程:取消新信息并嘗試預(yù)測這些信息。 我會(huì)把這留給你的創(chuàng)造力蛇摸。
- 更好的建模技術(shù)备图。
決策樹
決策樹是另一種方法做一個(gè)預(yù)測模型。 眾所周知,提供比邏輯回歸模型精度高赶袄。
model = DecisionTreeClassifier()
predictor_var = ['Credit_History','Gender','Married','Education']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:81.930%交叉驗(yàn)證得分:76.656%
在這里揽涮,基于分類變量的模型無法產(chǎn)生影響,因?yàn)樾庞脷v史主導(dǎo)著它們饿肺。 讓我們嘗試一些數(shù)值變量:
predictor_var = ['Credit_History','Loan_Amount_Term','LoanAmount_log']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:89.414%交叉驗(yàn)證得分:68.397%
在這里蒋困,我們觀察到雖然增加變量的準(zhǔn)確性上升,但交叉驗(yàn)證錯(cuò)誤卻下降了敬辣。 這是模型過度擬合數(shù)據(jù)的結(jié)果雪标。
隨機(jī)森林
隨機(jī)森林是另一個(gè)算法解決分類問題零院。
隨機(jī)森林的一個(gè)優(yōu)點(diǎn)是我們可以使它適用于所有功能,并返回一個(gè)功能重要性矩陣村刨,可用于選擇功能告抄。
model = RandomForestClassifier(n_estimators=100)
predictor_var = ['Gender', 'Married', 'Dependents', 'Education',
'Self_Employed', 'Loan_Amount_Term', 'Credit_History', 'Property_Area',
'LoanAmount_log','TotalIncome_log']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:100.000%交叉驗(yàn)證得分:78.179%
在這里,我們看到,訓(xùn)練集的精度是100%。這是最終的過度擬合的例子,可以通過兩種方式解決:
- 減少數(shù)量的預(yù)測
- 優(yōu)化模型參數(shù)
首先嵌牺,我們看到功能重要性矩陣打洼,我們將從中獲取最重要的功能。
#Create a series with feature importances:
featimp = pd.Series(model.feature_importances_, index=predictor_var).sort_values(ascending=False)
print (featimp)
Credit_History 0.272855
TotalIncome_log 0.263706
LoanAmount_log 0.222033
Dependents 0.051060
Property_Area 0.048117
Loan_Amount_Term 0.045753
Married 0.025963
Education 0.025323
Gender 0.023837
Self_Employed 0.021353
dtype: float64
讓我們使用前5個(gè)變量來創(chuàng)建模型髓梅。 另外拟蜻,我們將稍微修改隨機(jī)森林模型的參數(shù):
model = RandomForestClassifier(n_estimators=25, min_samples_split=25, max_depth=7, max_features=1)
predictor_var = ['TotalIncome_log','LoanAmount_log','Credit_History','Dependents','Property_Area']
classification_model(model, df,predictor_var,outcome_var)
-> 精度:82.899%交叉驗(yàn)證得分:80.949%
請(qǐng)注意,雖然準(zhǔn)確度降低了枯饿,但交叉驗(yàn)證得分正在提高酝锅,表明該模型已經(jīng)很好地推廣。 請(qǐng)記住奢方,隨機(jī)森林模型并不完全可重復(fù)搔扁。
你會(huì)注意到,即使在隨機(jī)森林上進(jìn)行了一些基本的參數(shù)調(diào)整之后蟋字,我們的交叉驗(yàn)證精度也只比原始邏輯回歸模型略好稿蹲。 這個(gè)練習(xí)給了我們一些非常有趣和獨(dú)特的學(xué)習(xí):
- 使用更復(fù)雜的模型并不能保證更好的結(jié)果。
- 在不理解基本概念的情況下鹊奖,避免將復(fù)雜的建模技術(shù)用作模型苛聘。 這樣做會(huì)增加過度擬合的傾向,從而使您的模型不易解釋
- 特征工程是成功的關(guān)鍵忠聚。 每個(gè)人都可以使用Xgboost模型设哗,但真正的藝術(shù)和創(chuàng)造力在于增強(qiáng)特性以更好地適應(yīng)模型。