【金融风控系列】_[1]_贷款违约预测

P粉084495128
发布: 2025-07-21 17:32:20
原创
295人浏览过
本文围绕天池贷款违约预测赛题,介绍零基础入门金融风控的实现过程。使用超过120万条贷款记录数据,对比多种数据不平衡处理方法,以CatBoost为基分类器,经5折交叉验证,结合过采样的模型线上表现较好(AUC 0.7347),SMOTE和BalanceCascade效果欠佳,为相关任务提供参考。

☞☞☞AI 智能聊天, 问答助手, AI 智能搜索, 免费无限量使用 DeepSeek R1 模型☜☜☜

【金融风控系列】_[1]_贷款违约预测 - php中文网

零基础入门金融风控-贷款违约预测

该赛题来自 TIANCHI 零基础入门系列,仅用作学习交流

该数据来自某信贷平台的贷款记录,总数据量超过120w,包含47列变量信息,其中15列为匿名变量。为了保证比赛的公平性,将会从中抽取80万条作为训练集,20万条作为测试集A,20万条作为测试集B,同时会对employmentTitle、purpose、postCode和title等信息进行脱敏。

字段表

Field Description
id 为贷款清单分配的唯一信用证标识
loanAmnt 贷款金额
term 贷款期限(year)
interestRate 贷款利率
installment 分期付款金额
grade 贷款等级
subGrade 贷款等级之子级
employmentTitle 就业职称
employmentLength 就业年限(年)
homeOwnership 借款人在登记时提供的房屋所有权状况
annualIncome 年收入
verificationStatus 验证状态
issueDate 贷款发放的月份
purpose 借款人在贷款申请时的贷款用途类别
postCode 借款人在贷款申请中提供的邮政编码的前3位数字
regionCode 地区编码
dti 债务收入比
delinquency_2years 借款人过去2年信用档案中逾期30天以上的违约事件数
ficoRangeLow 借款人在贷款发放时的fico所属的下限范围
ficoRangeHigh 借款人在贷款发放时的fico所属的上限范围
openAcc 借款人信用档案中未结信用额度的数量
pubRec 贬损公共记录的数量
pubRecBankruptcies 公开记录清除的数量
revolBal 信贷周转余额合计
revolUtil 循环额度利用率,或借款人使用的相对于所有可用循环信贷的信贷金额
totalAcc 借款人信用档案中当前的信用额度总数
initialListStatus 贷款的初始列表状态
applicationType 表明贷款是个人申请还是与两个共同借款人的联合申请
earliesCreditLine 借款人最早报告的信用额度开立的月份
title 借款人提供的贷款名称
policyCode 公开可用的策略_代码=1新产品不公开可用的策略_代码=2
n系列匿名特征 匿名特征n0-n14,为一些贷款人行为计数特征的处理

参考:

[1] https://github.com/caozichuan/TianChi_loadDefault/blob/main/GitHub_loadDefault/model/xgb_github.ipynb

[2] https://tianchi.aliyun.com/notebook-ai/detail?spm=5176.21852664.0.0.4f70379c1gFeCt&postId=129321

[3] https://imbalanced-ensemble.readthedocs.io/en/latest/index.html

[4] https://blog.csdn.net/qq_31367861/article/details/111145816?spm=5176.21852664.0.0.22686e12UZfkmZ

文献4方法线上提交分数为0.7391
登录后复制

       

[5] https://blog.csdn.net/qq_44694861/article/details/109753004?spm=5176.21852664.0.0.667f4288swn2OQ

本项目主要是对金融风控中常见的数据不平衡方法进行对比,以及对 self-paced-ensemble 包进行学习

使用的方法如下:

  • 无处理
  • SMOTE算法

SMOTE(Synthetic Minority Oversampling Technique),合成少数类过采样技术.它是基于随机过采样算法的一种改进方案,为了克服随机过采样算法泛化能力差的缺点,SMOTE算法的对少数类样本近邻进行采样,根据少数类样本人工合成新样本添加到数据集中。

采风问卷
采风问卷

采风问卷是一款全新体验的调查问卷、表单、投票、评测的调研平台,新奇的交互形式,漂亮的作品,让客户眼前一亮,让创作者获得更多的回复。

采风问卷 20
查看详情 采风问卷
  • SPE算法

Liu Z , Cao W , Gao Z , et al. Self-paced Ensemble for Highly Imbalanced Massive Data Classification[J]. 2019.

  • 过采样算法

重复正样本,使得正样本与负样本比例接近 1 : 1

  • 欠采样算法

从数量多的样本里面随机选择样本进行抛弃,为了避免随机性影响,我们独立训练多个模型进行简单平均

  • BalanceCascade算法

Liu, X. Y., Wu, J., & Zhou, Z. H. “Exploratory undersampling for class-imbalance learning.” IEEE Transactions on Systems, Man, and Cybernetics, Part B (Cybernetics) 39.2 (2008): 539-550

注意事项

  • 运行主要有两部分,数据处理 和 模型选择 ,根据注释部分,自己进行数据处理和算法组合。默认CBT模型+过采样算法。
In [1]
#!pip install pandas --user#!pip install lightgbm --user#!pip install xgboost --user!pip install catboost --user
!pip install joblib --user
!pip install scikit-learn --user
!pip install imblearn --user
!pip install imbalanced-ensemble --user
!pip self-paced-ensemble --user
登录后复制
   
In [2]
import pandas as pdimport datetimeimport warnings
warnings.filterwarnings('ignore')from sklearn.model_selection import StratifiedKFold#warnings.filterwarnings('ignore')#%matplotlib inlinefrom sklearn.metrics import roc_auc_score## 数据降维处理的from sklearn.model_selection import train_test_split  
from catboost import CatBoostClassifierimport imbalanced_ensemble as imbensfrom collections import Counterfrom imbalanced_ensemble.sampler.over_sampling import     SMOTE 
import numpy as np
train=pd.read_csv("./data/data53042/train.csv")
testA=pd.read_csv("./data/data53042/testA.csv")

numerical_fea = list(train.select_dtypes(exclude=['object']).columns)
category_fea = list(filter(lambda x: x not in numerical_fea,list(train.columns)))
label = 'isDefault'numerical_fea.remove(label)#按照中位数填充数值型特征train[numerical_fea] = train[numerical_fea].fillna(train[numerical_fea].median())
testA[numerical_fea] = testA[numerical_fea].fillna(testA[numerical_fea].median())#按照众数填充类别型特征train[category_fea] = train[category_fea].fillna(train[category_fea].mode())
testA[category_fea] = testA[category_fea].fillna(testA[category_fea].mode())def make_fea(data):
    data['issueDate'] = pd.to_datetime(data['issueDate'],format='%Y-%m-%d')
    startdate = datetime.datetime.strptime('2007-06-01', '%Y-%m-%d')    #构造时间特征
    data['issueDateDT'] = data['issueDate'].apply(lambda x: x-startdate).dt.days

    data['grade'] = data['grade'].map({'A':1,'B':2,'C':3,'D':4,'E':5,'F':6,'G':7})
    data['subGrade'] = data['subGrade'].map({'E2':1,'D2':2,'D3':3,'A4':4,'C2':5,'A5':6,'C3':7,'B4':8,'B5':9,'E5':10,        'D4':11,'B3':12,'B2':13,'D1':14,'E1':15,'C5':16,'C1':17,'A2':18,'A3':19,'B1':20,        'E3':21,'F1':22,'C4':23,'A1':24,'D5':25,'F2':26,'E4':27,'F3':28,'G2':29,'F5':30,        'G3':31,'G1':32,'F4':33,'G4':34,'G5':35})

    data = pd.get_dummies(data, columns=['subGrade', 'homeOwnership', 'verificationStatus', 'purpose', 'regionCode'], drop_first=True)
    data['employmentLength'] = data['employmentLength'].map({'NaN':-1,'1 year':1,'2 years':2,'3 years':3,'4 years':4,'5 years':5,'6 years':6,'7 years':7,'8 years':8,'9 years':9,'10+ years':10,'< 1 year':0})
    data['earliesCreditLine'] = data['earliesCreditLine'].apply(lambda s: int(s[-4:]))    for item in ['n0','n1','n2','n2.1','n4','n5','n6','n7','n8','n9','n10','n11','n12','n13','n14']:
        data['grade_to_mean_' + item] = data['grade'] / data.groupby([item])['grade'].transform('mean')
        data['grade_to_std_' + item] = data['grade'] / data.groupby([item])['grade'].transform('std')
    data['n15']=data['n8']*data['n10']    return data# 特征工程 简单处理train = make_fea(train)
testA = make_fea(testA)print(train.shape)print(testA.shape)print("数据预处理完成!")  
sub=testA[['id']].copy()
sub['isDefault']=0testA=testA.drop(['id','issueDate'],axis=1)
data_x=train.drop(['isDefault','id','issueDate'],axis=1)

data_y=train[['isDefault']].copy()

col=['grade','subGrade','employmentTitle','homeOwnership','verificationStatus','purpose','postCode','regionCode',     'initialListStatus','applicationType','policyCode']for i in data_x.columns:    if i in col:
        data_x[i] = data_x[i].astype('str')for i in testA.columns:    if i in col:
        testA[i] = testA[i].astype('str')

answers = []
mean_score = 0n_folds = 5sk = StratifiedKFold(n_splits=n_folds, shuffle=True, random_state=2019)print(data_x.shape)print(testA.shape)# 在测试集中有部分特征训练集中没有,进行处理COLNAME = data_x.columns
testA = testA[COLNAME]# 处理INF NAN ,替换成 -1 注意:np.inf和-np.inf是不同的两个值,这里经常遇到忘记处理后者引发错误data_x.replace([np.inf, -np.inf, np.nan], -1, inplace=True)
testA.replace([np.inf, -np.inf, np.nan], -1, inplace=True)#  -----重复正样本,因为原始数据比例约为3:1 因此对正样本重复三次拼接到原始数据中-----a = [i for i, x in enumerate(data_y.values) if x[0]==1]
all_1 = data_x.iloc[a]
all_y = pd.DataFrame(np.ones(all_1.shape[0],dtype=int),columns=['isDefault'])print(all_y.shape)print(data_x.shape,data_y.shape)for i in range(3):
    data_y= pd.concat([data_y,all_y],axis=0)
    data_x = pd.concat([data_x,all_1],axis=0)    print(data_x.shape,data_y.shape)
data_x.reset_index(drop=True,inplace =True)
data_y.reset_index(drop=True,inplace =True)'''
# -----使用SMOTE算法对负样本进行扩充-----
sm = SMOTE(random_state=42)
data_x, data_y = sm.fit_resample(data_x, data_y)
print('Resampled dataset' , data_y.value_counts())
'''
登录后复制
   

基础模型定义及训练

使用CatBoost分类模型作为基准模型

In [ ]
model=CatBoostClassifier(
            loss_function="Logloss",
            eval_metric="AUC",
            task_type="CPU",
            learning_rate=0.1,
            iterations=500,
            random_seed=2020,
            verbose=500,
            depth=7)for train, test in sk.split(data_x, data_y):
    x_train = data_x.iloc[train]
    y_train = data_y.iloc[train]
    x_test = data_x.iloc[test]
    y_test = data_y.iloc[test]    '''
    # -----使用SPE 算法对不平衡数据进行处理-----
    clf = imbens.ensemble.SelfPacedEnsembleClassifier(
        base_estimator = model,#基准分类模型 可以自定义,需要模型包含fit等方法,具体信息请查看参考文献3
        n_estimators = 5,
        random_state=49
    ).fit(x_train, y_train)
    '''
    # -----使用BalanceCascade 算法对不平衡数据进行处理-----
    '''
    clf = imbens.ensemble.BalanceCascadeClassifier(        
        base_estimator = model,#基准分类模型 可以自定义,需要模型包含fit等方法,具体信息请查看参考文献3
        n_estimators = 5,
        random_state=49
    ).fit(x_train, y_train)
    '''

    # 基准分类模型
    clf = model.fit(x_train,y_train)#, eval_set=(x_test,y_test),cat_features=col)

    yy_pred_valid=clf.predict_proba(x_test)[:,-1]    print('cat验证的auc:{}'.format(roc_auc_score(y_test, yy_pred_valid)))
    mean_score += roc_auc_score(y_test, yy_pred_valid) / n_folds
    y_pred_valid = clf.predict_proba(testA)[:,-1]
    answers.append(y_pred_valid)print('mean valAuc:{}'.format(mean_score))
cat_pre=sum(answers)/n_folds
sub['isDefault']=cat_pre
sub.to_csv('金融预测.csv',index=False)
登录后复制
   

欠采样模型训练

In [ ]
model=CatBoostClassifier(
            loss_function="Logloss",
            eval_metric="AUC",
            task_type="CPU",
            learning_rate=0.1,
            iterations=500,
            random_seed=2020,
            verbose=500,
            depth=7)#----- 欠采样模型 -----a = [i for i, x in enumerate(data_y.values) if x[0]==1]
all_1 = data_x.iloc[a]
all_y1 = pd.DataFrame(np.ones(all_1.shape[0]),columns=['isDefault'])
all_y0 = pd.DataFrame(np.ones(all_y.shape[0]),columns=['isDefault'])print(all_y1.shape)#for i in range(4): # 数据比1:4+i= 0all_0 = data_x.iloc[i*all_y1.shape[0]:(i+1)*all_y1.shape[0],:]
data_y_= pd.concat([all_y1,all_y0],axis=0)
data_x_ = pd.concat([all_1,all_0],axis=0)print(data_x_.shape,data_y_.shape,all_0.shape)for train, test in sk.split(data_x, data_y):
    x_train = data_x.iloc[train]
    y_train = data_y.iloc[train]
    x_test = data_x.iloc[test]
    y_test = data_y.iloc[test]    # 基准分类模型
    #clf = model.fit(x_train,y_train)#, eval_set=(x_test,y_test),cat_features=col)

    clf = imbens.ensemble.SelfPacedEnsembleClassifier(
        base_estimator = model,#基准分类模型 可以自定义,需要模型包含fit等方法,具体信息请查看参考文献3
        n_estimators = 5,
        random_state=49
    ).fit(x_train, y_train)
    yy_pred_valid=clf.predict_proba(x_test)[:,-1]    print('cat验证的auc:{}'.format(roc_auc_score(y_test, yy_pred_valid)))
    mean_score += roc_auc_score(y_test, yy_pred_valid) / n_folds
    y_pred_valid = clf.predict_proba(testA)[:,-1]
    answers.append(y_pred_valid)print('mean valAuc:{}'.format(mean_score))
cat_pre=sum(answers)/(n_folds) # 数据比1:4sub['isDefault']=cat_pre
sub.to_csv('金融预测.csv',index=False)
登录后复制
   

总结

  • 本项目主要以CBT算法为基分类器对比了几种常用的数据不平衡的处理效果,关于数据特征构建的知识可以查看开头参考文献。

数据的对比提交结果如下:

数据集 TIANCHI-贷款违约预测(ONLine)
比例 4.01(80W)
指标 AUC(线下五折验证/线上)
CaTBoost+SPE(5) 0.7348/0.7328
CaTBoost 0.7354/0.7338
CaTBoost+SMOTE 0.9334/0.6949
CaTBoost+过采样 0.7477/0.7346
CaTBoost+欠采样 0.7354/0.7338
CaTBoost+BalanceCascade(5) 0.6052/0.6032
CaTBoost+SPE(5)+过采样 0.7485/0.7347

imbalanced-ensemble库中包含了许多其他的非平衡算法,有兴趣的同学可以关注参考文献[3]

  • 此外,在训练中,随着基模型数量的增加此数据上的分类表现有所下降,这可能是由于此数据失衡仅4:1,不足以体现算法优势。

以上就是【金融风控系列】_[1]_贷款违约预测的详细内容,更多请关注php中文网其它相关文章!

360借条
360借条

3分钟审核,最快5分钟放款,极速到账,低服务费,年化综合息费率7.2%起。

下载
来源:php中文网
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
最新问题
开源免费商场系统广告
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新 English
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号