新闻中心

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

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

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

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

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

该赛题来自 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算法的对少数类样本近邻进行采样,根据少数类样本人工合成新样本添加到数据集中。

美图云修 美图云修

商业级AI影像处理工具

美图云修 50 查看详情 美图云修
  • 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=2025,
            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=2025,
            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]_贷款违约预测的详细内容,更多请关注其它相关文章!


# 数据处理  # 高州seo优化关键词  # 浦江网站建设流程设计  # 百度营销推广教程  # 康复学科营销推广方案  # 网站建设与管理课程学啥  # 武汉推广招人网站排名榜  # 昆明长沙seo费用信誉保障  # 渭南富平seo优化  # 开州区可靠网站建设  # 网站优化设计名词解释  # 安装包  # 对不  # 一键  # git  # 中文网  # 请查看  # 不平衡  # 自定义  # 线上  # 美图  # type  # descript  # red  # yy  # ai  # qq  # cad 


相关栏目: 【 行业资讯67740 】 【 技术百科0 】 【 网络运营39195


相关推荐: 夸克转存中是什么意思  双十一的哪一天最优惠呢  如何判断固态硬盘端口  交管12123协议头不完整是什么原因  苹果16有哪些系统  typescript全局配置放哪里  type-c全能接口是什么意思  如何查看win10版本命令行  市盈率动亏损是什么意思  j*a数组怎么存满  得物上怎么样申请退换货 得物上退换货详细指南(包含海外)  如何设置sql命令  play的三人称单数和过去式  电脑type-c接口是什么意思  linux如何使用db2命令  linux如何查看命令的参数  如何给电脑加装固态硬盘  typescript怎么判断单选按钮  typescript怎么使用map  春运抢票可以抢几次票  春运抢票需要抢几天  ka是什么意思  如何查看固态硬盘分区  windows 如何连接ftp命令行  win10windows资源管理器在哪里打开  抖音GMV是什么_抖音GMV是什么意思  单片机是怎么计时的  折叠屏手机信号哪个最强  苹果16有哪些亮点功能  如何通过命令检测u盘启动  电脑命令如何删除账号  数组和J*A怎么打  如何修改cad命令  typescript多久能学会  笔记本如何选择固态硬盘  路亚竿上的power是什么意思  划水是什么意思  如何更新typescript  如何查找固态硬盘  新版路由器如何设置路由命令  linux如何跳回命令行界面  typescript有什么框架  苹果16系统有哪些功能  driver是什么意思  满射和单射定义  5G类似微信的聊天软件有哪些  arp命令如何使用  建伍遥控器power是什么意思  苹果16颜色有哪些  爱玛电动车power模式是什么意思 

搜索