提示:文章内容来源于金融统计分析课题作业
文章目录
前言
对于银行等贷款金融机构来说,监控借款客户的违约风险是保证贷款安全的重要措施。建立一个信贷违约预测模型一方面可以事先对借款客户进行风险识别,为确认是否放贷、放贷多少、风险补偿多少提供决策依据;另一方面,可以对已借款客户进行违约风险监督,当客户的生活、经济状况发生变化时,能及时警示风险,采取措施保护债权。
一、模型简介
决策树模型是一种基于树结构的监督学习算法,常用于解决分类问题(同样可以用于解决回归问题)。它通过对输入数据集进行分割,最终生成一个树状模型,其中每个节点表示一个特征,每个叶节点表示一个类别或数值。 决策树的构建过程通常从根节点开始,选择一个最优的特征来进行数据集的分割。常用的特征选则依据有信息增益、基尼指数。 对决策树模型不了解的看官可以看看我的精选笔记😳[低调]:机器学习 | 关于决策树分类模型,你学得怎么样了?
二、建模思路
1、准备一份信贷违约统计数据,并对数据进行特征编码(因为机器学习算法通常需要处理数值型数据,而不能直接处理类别型或文本型数据。)
2、处理数据中的一些无效数据,如:缺失值、错误值(例:年龄144)等
3、初步建立决策树模型,此时决策树模型中的参数尚未调整优化
4、评估初步建立的模型,这一步会用到预测正确率、AUC得分、ROC曲线和KS曲线
5、对决策树模型进行参数调优,如决策树最大深度等
6、使用第5步得出的参数,重新建立最最优参数决策树模型
7、K折交叉验证最优参数模型,并画出建立的决策树模型
三、代码实现
import pandas as pd
data_path = 'credit_risk_dataset.csv'
data = pd.read_csv(data_path)
data.head()
obj_cols_data = data.select_dtypes(exclude = 'number')
for column in obj_cols_data.columns:
print(column)
print(obj_cols_data[column].value_counts())
print('\n')
# 将非数值列转换成数值列
dict1 = {'RENT':0, 'MORTGAGE':1, 'OWN':2, 'OTHER':3}
dict2 = {'EDUCATION':0,'MEDICAL':1,'VENTURE':2,'PERSONAL':3,'DEBTCONSOLIDATION':4,'HOMEIMPROVEMENT':5}
dict3 = {'A':0,'B':1,'C':2,'D':3,'E':4,'F':5,'G':6}
dict4 = {'N':0, 'Y':1}
data.person_home_ownership.replace(dict1, inplace=True)
data.loan_intent.replace(dict2, inplace=True)
data.loan_grade.replace(dict3, inplace = True)
data.cb_person_default_on_file.replace(dict4, inplace = True)
data
data = data.loc[(data.person_age>=20) & (data.person_age<=100)]
# 工作年限不超过年龄
data = data.loc[data.person_age>=data.person_emp_length]
data = data.dropna()
data
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 显示中文
plt.rcParams['axes.unicode_minus'] = False # 显示负号
rows = 3
cols = 4
fig, axes = plt.subplots(rows, cols, figsize=(12, 9))
for i, column in enumerate(data.columns):
ax = axes[i // cols, i % cols]
data[column].hist(ax=ax)
ax.set_title(column)
plt.tight_layout()
plt.show()
X=data.drop(columns='cb_person_default_on_file')
y=data['cb_person_default_on_file']
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=1)
from sklearn.tree import DecisionTreeClassifier # 需要参数优化
model=DecisionTreeClassifier(max_depth=3,random_state=123) # max_depth设置决策树最大深度(简单理解就是判断次数)
model.fit(X_train,y_train)
y_pre=model.predict(X_test)
score=model.score(X_test,y_test)
print('accuracy score:','{:.2%}'.format(score))
from sklearn.metrics import confusion_matrix
m=confusion_matrix(y_test,y_pre)
m_df=pd.DataFrame(m,index=['0_true','1_true'],columns=['0_predict','1_predict'])
print(m_df)
y_pre_proba=model.predict_proba(X_test)
proba_df=pd.DataFrame(y_pre_proba,columns=['0_不违约概率','1_违约概率'])
print(proba_df)
features=data.drop(columns='cb_person_default_on_file').columns
importance=model.feature_importances_
imp_df=pd.DataFrame()
imp_df['features']=features
imp_df['importance']=importance
imp_df.sort_values(by='importance',ascending=False,inplace=True)
print(imp_df)
from sklearn.metrics import classification_report
print(classification_report(y_test,y_pre))
from sklearn.metrics import roc_curve
fpr,tpr,threshed=roc_curve(y_test,y_pre_proba[:,1])
d=pd.DataFrame()
d['threshed']=list(threshed)
d['false_positive_ratio']=list(fpr)
d['true_positive_ratio']=list(tpr)
d['TPR-FPR_ratio']=d.true_positive_ratio-d.false_positive_ratio
print(d)
from sklearn.metrics import roc_auc_score
auc_score=roc_auc_score(y_test,y_pre_proba[:,1])
print('auc_score:','{:.2%}'.format(auc_score))
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.plot(d.false_positive_ratio,d.true_positive_ratio)
plt.fill_between(d.false_positive_ratio,0,d.true_positive_ratio,alpha=0.8)
plt.text(0.5,0.5,'AUC_score = {:.2%}'.format(auc_score))
plt.title('ROC_Curve')
plt.xlabel('false_positive_ratio')
plt.ylabel('true_positive_ratio')
plt.grid()
ks_v=np.max(d.true_positive_ratio-d.false_positive_ratio)
threshed_=d.loc[d['TPR-FPR_ratio']==ks_v].iat[0,0]
print('KS值:','{:.2%}'.format(ks_v))
# KS值小于0.2,模型区分能力较弱;
# KS值在0.2~0.3之间,模型具有一定区分能力;
# KS值在0.3~0.5之间,模型具有较强区分能力;
# KS值不是越大越好,如果KS值大于0.75,往往代表模型有异常。商业实践中,KS值处于0.2~0.3之间就已经挺不错了
plt.subplot(122)
plt.plot(d.threshed[1:],d.true_positive_ratio[1:],label='true_positive_ratio')
plt.plot(d.threshed[1:],d.false_positive_ratio[1:],label='false_positive_ratio')
plt.plot(d.threshed[1:],d.true_positive_ratio[1:]-d.false_positive_ratio[1:],label='TPR-FPR_ratio')
plt.annotate('threshed = {:.2%}'.format(threshed_)+'\n'+'KS_value = {:.2%}'.format(ks_v),xy=(threshed_,ks_v),
arrowprops={'facecolor':'green', 'shrink':0.0})
plt.title('KS_curve')
plt.xlabel('threshed')
plt.ylabel('ratio')
plt.legend()
plt.grid()
from sklearn.model_selection import GridSearchCV
parameters={'max_depth':[1,2,3,4,5,6,7,8,9],'criterion':['gini','entropy']}
the_model=DecisionTreeClassifier()
grid_search=GridSearchCV(the_model,parameters,cv=5,scoring='roc_auc')
grid_search.fit(X_train,y_train)
best_max_depth=grid_search.best_params_['max_depth']
best_criterion=grid_search.best_params_['criterion']
print(grid_search.best_score_)
print('best_params: ',grid_search.best_params_)
# max_depth设置决策树最大深度(简单理解就是判断次数)
# 将模型参数设置为最优参数,重新建立模型:
model=DecisionTreeClassifier(max_depth=best_max_depth,criterion=best_criterion,random_state=123)
model.fit(X_train,y_train)
y_pre=model.predict(X_test)
score=model.score(X_test,y_test)
print('accuracy score:','{:.2%}'.format(score))
m=confusion_matrix(y_test,y_pre)
m_df=pd.DataFrame(m,index=['0_true','1_true'],columns=['0_predict','1_predict'])
print(m_df)
y_pre_proba=model.predict_proba(X_test)
proba_df=pd.DataFrame(y_pre_proba,columns=['0_no_default_prob','1_default_prob'])
print(proba_df)
features=data.drop(columns='cb_person_default_on_file').columns
importance=model.feature_importances_
imp_df=pd.DataFrame()
imp_df['features']=features
imp_df['importance']=importance
imp_df.sort_values(by='importance',ascending=False,inplace=True)
print(imp_df)
print(classification_report(y_test,y_pre))
fpr,tpr,threshed=roc_curve(y_test,y_pre_proba[:,1])
d=pd.DataFrame()
d['threshed']=list(threshed)
d['false_positive_ratio']=list(fpr)
d['true_positive_ratio']=list(tpr)
d['TPR-FPR_ratio']=d.true_positive_ratio-d.false_positive_ratio
print(d)
auc_score=roc_auc_score(y_test,y_pre_proba[:,1])
print('auc_score:','{:.2%}'.format(auc_score))
plt.figure(figsize=(15,5))
plt.subplot(121)
plt.plot(d.false_positive_ratio,d.true_positive_ratio)
plt.fill_between(d.false_positive_ratio,0,d.true_positive_ratio,alpha=0.8)
plt.text(0.5,0.5,'AUC_score = {:.2%}'.format(auc_score))
plt.title('ROC_Curve after gridsearch')
plt.xlabel('false_positive_ratio')
plt.ylabel('true_positive_ratio')
plt.grid()
ks_v=np.max(d.true_positive_ratio-d.false_positive_ratio)
threshed_=d.loc[d['TPR-FPR_ratio']==ks_v].iat[0,0]
print('KS值:','{:.2%}'.format(ks_v))
# KS值小于0.2,模型区分能力较弱;
# KS值在0.2~0.3之间,模型具有一定区分能力;
# KS值在0.3~0.5之间,模型具有较强区分能力;
# KS值不是越大越好,如果KS值大于0.75,往往代表模型有异常。商业实践中,KS值处于0.2~0.3之间就已经挺不错了
plt.subplot(122)
plt.plot(d.threshed[1:],d.true_positive_ratio[1:],label='true_positive_ratio')
plt.plot(d.threshed[1:],d.false_positive_ratio[1:],label='false_positive_ratio')
plt.plot(d.threshed[1:],d.true_positive_ratio[1:]-d.false_positive_ratio[1:],label='TPR-FPR_ratio')
plt.annotate('threshed = {:.2%}'.format(threshed_)+'\n'+'KS_value = {:.2%}'.format(ks_v),xy=(threshed_,ks_v),
arrowprops={'facecolor':'green', 'shrink':0.0})
plt.title('KS_curve after gridsearch')
plt.xlabel('threshed')
plt.ylabel('ratio')
plt.legend()
plt.grid()
plt.suptitle('Decision_Tree_Classifier')
plt.show()
from sklearn.model_selection import cross_val_score
cv = 5
K_acc = cross_val_score(model, X, y, cv = cv)
K_roc_auc = cross_val_score(model, X, y, cv = 5, scoring = 'roc_auc')
print('K_acc:',K_acc)
print('K_acc_mean:',K_acc.mean())
print('K_acc_std:',K_acc.std())
print('K_roc_auc:',K_roc_auc)
print('K_roc_auc_mean:',K_roc_auc.mean())
print('K_roc_auc_std:',K_roc_auc.std())
# 画出决策树
from sklearn import tree
plt.figure(figsize=(18,12))
tree.plot_tree(model);
plt.show()
四、总结
决策树模型显示,在最大深度为3的参数下得出如下结果,命中率(TPR)=34%。模型整体的预测正确率达到了83%。对于二分类问题,ROC曲线和KS曲线是较为理想的模型评估手段,本文使用这两种图形对模型的结构进行评估。根据ROC曲线的位置,可以判断预测准确率。曲线越接近左上角(X越小,Y越大),预测准确率越高。ROC曲线下的面积(AUC)。AUC值越大,预测准确率越高。模型的ROC曲线陡峭,接近(0,1)左上角,AOC值达到了90.18%,这说明模型的预测准确率较高。
KS曲线以命中率和假警报率作为纵轴,以阈值作为横轴,是一种用于衡量分类模型性能的工具,可以很好地衡量命中率和假警报率之间的关系。如下所示,随着阈值的上升,假警报率随之下降;命中率则在0.4892之前保持不变,当阈值超过当阈值接近0.4892时,命中率开始快速下降。因此在0.4892处有最大的KS值79.09%。如果KS曲线贴近横坐标轴,表示分类器的性能较差;如果曲线贴近纵坐标轴,表示分类器的性能较好。从图中可知,该模型的性能处于较好水平。
查看模型的特征重要度,可以看到loan_grade占很大的权重。原因可能是因为loan_grade已经包含了其他特征变量的信息。
文章就到写到这了,点赞关注后私信小编,可获取完整代码和数据库哦❤
注:(可以自取代码和数据了)如果没有及时回复,可搜索微信公众号:课题怪。然后私信:C20231114 可获取代码、D20231114 可获取数据。