2021 CCF大数据与计算智能大赛个贷违约预测top 73 解决方案

一、概述

这是我第二次参加大数据类型的竞赛,也是第一次接触金融类的题目,这一题可以称作CCF BDCI这一年的究极卷王题,3200个队伍参加,1300多个队伍提交,比其他赛题多了几倍,最后尽力也只拿下B榜73/3246的名次。
在次记录自己的解题过程以及所思所想。
赛题地址:https://www.datafountain.cn/competitions/530
在这里插入图片描述

二、解题过程

2.1 数据

本次的数据由3个表组成,分别为个人贷款违约记录数据train_public.csv,某网络信用贷产品违约记录数据train_internet_public.csv,测试集test_public.csv。
数据说明请参考:https://www.datafountain.cn/competitions/530/datasets

通过查看数据,我们可以得知,这三个表可以大致理解为:和测试集分布较为接近的训练集(一万条)train_public,和测试集分布不同的训练集补充train_inte(70多万条),测试集。
很显然,本题的意思在于从补充测试集中找寻合适的数据扩充到原本的数据集中进行训练,然后预测提分,怎么样找到合适的数据成为本题的关键。

对于原始的数据,有一些初步的处理:

  • 对于时间类型的数据,转化为统一的time格式,并可以细化为年,月,周等
  • 对于string类型表达的数据,如工作类型等编码为数字类型
  • 将空值用均值进行填充

对三张表均进行上述操作,构建最基本的三张表

2.2 构建基线

参考社区分享的基线,构建LGBM模型

        clf = LGBMClassifier(
            n_estimators=4000,
            learning_rate=0.03,
            num_leaves=2 ** 5,
            colsample_bytree=.65,
            subsample=.9,
            max_depth=5,
            #             max_bin=250,
            reg_alpha=.3,
            reg_lambda=.3,
            min_split_gain=.01,
            min_child_weight=2,
        )

首先测试仅将train_public一万条数据导入lgbm中进行训练并测试,采用5折交叉验证,最终的结果为0.8786,这即为最初的基线,在我看来,跑通代码是比赛的第一步,也是较为关键的一步o(╥﹏╥)o

2.3 进阶思路一

同样参考社区提出的方法,第一个思路在于先使用train_public训练lgbm,然后使用训练得到的lgbm预测扩充数据集train_inte,设定一个筛选阈值,从中选择预测较为准确的样本。举个例子,我们根据原始训练集训练了lgbm,然后使用该lgbm预测train_inte,发现预测值<0.08的值(预测为0)其真实标签也为0,即预测全对,则我们将预测值<0.08的样本全部纳入原本训练集中进行扩充,此时数据来到7-10万条,代码大致如下:

#首先训练原始样本
oof_preds, IntePre, importances = train_model(train_data, train_inteSame, y, folds)

IntePre['isDef'] = train_inte['is_default']
from sklearn.metrics import roc_auc_score

roc_auc_score(IntePre['isDef'], IntePre.isDefault)
## 选择阈值0.05,从internet表中提取预测小于该概率的样本,并对不同来源的样本赋予来源值
InteId = IntePre.loc[IntePre.isDefault < 0.08, 'loan_id'].tolist()

train_data['dataSourse'] = 1
test_public['dataSourse'] = 1
train_inteSame['dataSourse'] = 0
train_inteSame['isDefault'] = train_inte['is_default']
use_te = train_inteSame[train_inteSame.loan_id.isin(InteId)].copy()
#扩充数据
data = pd.concat([train_data, test_public, use_te]).reset_index(drop=True)

del data
del train_data, test_public

print(train.columns)
print(test.columns)
y = train['isDefault']
#再度训练以及预测
folds = KFold(n_splits=15, shuffle=True, random_state=2021)
oof_preds, test_preds, importances = train_model(train, test, y, folds)

使用该方法可以有效扩充数据集,线上分来到0.8852

2.4 进阶思路二

使用伪标签,该方法即先使用2.3中得到的模型预测测试集,然后再次设定一个阈值,将符合阈值的测试集数据纳入到训练集中,标签根据预测结果给定,此举可以进一步扩充数据集,使得模型看到更多类型的数据。
但值得注意的是,该方法要看赛事官方是否允许,本题中并未禁止
使用该方法后,线上分来到0.8925

2.5 进阶思路三

第三个思路我们在最后几天才想到,即使用聚类的思想,将三张表凑在一起进行聚类,将与测试集聚类在一起的样本挑出来作为训练样本。
经过实验我们发现聚类的结果将大部分训练集和测试集分为一类,可见其分布一致,而train_inte中的数据被分为几类,从中挑选与测试集聚类结果尽量相同的样本,经过我们的挑选,在40万-60万之间(多次实验,记不清了)。
参考代码(此处我们使用了Kmeans,但实际上我们还使用过BIRCH,最后时间紧迫来不及详细测试孰优孰劣):

# 综合分类数据集
from numpy import where
from sklearn.datasets import make_classification
from sklearn.cluster import Birch,MiniBatchKMeans,KMeans
from matplotlib import pyplot
import pandas as pd
import re
import numpy as np
from sklearn.preprocessing import LabelEncoder
# 定义数据集

train_data = pd.read_csv(r'D:\比赛\CCF_BDCI_Money\raw_data\train_public.csv')
test_public = pd.read_csv(r'D:\比赛\CCF_BDCI_Money\raw_data\test_public.csv')
train_inte = pd.read_csv(r'D:\比赛\CCF_BDCI_Money\raw_data\train_internet.csv')

def findDig(val):
    fd = re.search('(\d+-)', val)
    if fd is None:
        return '1-'+val
    return val + '-01'

work_year_dict = {
    '< 1 year': 0,
    '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,
}

class_dict = {
    'A': 1,
    'B': 2,
    'C': 3,
    'D': 4,
    'E': 5,
    'F': 6,
    'G': 7,
}

timeMax = pd.to_datetime('1-Dec-21')
train_data['work_year'] = train_data['work_year'].map(work_year_dict)
test_public['work_year'] = test_public['work_year'].map(work_year_dict)
train_inte['work_year'] = train_inte['work_year'].map(work_year_dict)

train_data['class'] = train_data['class'].map(class_dict)
test_public['class'] = test_public['class'].map(class_dict)
train_inte['class'] = train_inte['class'].map(class_dict)


train_data['earlies_credit_mon'] = pd.to_datetime(train_data['earlies_credit_mon'].map(findDig))
test_public['earlies_credit_mon'] = pd.to_datetime(test_public['earlies_credit_mon'].map(findDig))
train_inte['earlies_credit_mon'] = pd.to_datetime(train_inte['earlies_credit_mon'].map(findDig))

cat_cols = ['employer_type', 'industry']

for col in cat_cols:
    lbl = LabelEncoder().fit(train_data[col])
    train_data[col] = lbl.transform(train_data[col])
    test_public[col] = lbl.transform(test_public[col])
    train_inte[col] = lbl.transform(train_inte[col])


col_to_drop = ['issue_date', 'earlies_credit_mon','post_code','region']
train_data = train_data.drop(col_to_drop, axis=1)
test_public = test_public.drop(col_to_drop, axis=1 )
train_inte = train_inte.drop(col_to_drop, axis = 1)

train_inte = train_inte.drop(['sub_class'], axis = 1)

same_cols = list(set(train_data.columns.tolist()) & set(test_public.columns.tolist()) & set(train_inte.columns.tolist()))

data = pd.DataFrame()

import pdb
for col in same_cols:
    data[col] = pd.concat([train_data[col], test_public[col], train_inte[col]])
    data[col] = data[col].fillna(data[col].mean())

y = np.zeros(len(data))
i = 0
print(data.shape)
data = data.sample(765000)
data = data.reset_index(drop = True)

feat =[f for f in data.columns if f not in ['loan_id', 'user_id', 'isDefault']]
label_csv = pd.DataFrame()
label_csv['loan_id'] = data['loan_id']
label_csv['user_id'] = data['user_id']
col_name = 0

model = KMeans(n_clusters=3 , max_iter=1000)
model.fit(data[feat])
label_csv['kmeans_predict'] = model.predict(data[feat])
# print(label_csv)
label_csv.to_csv('聚类测试_3_no_batch.csv',index=False)


最后聚类得到的文件经过lgbm训练也能达到0.895附近

2.6 融合

最后我们将几种思路用过线上分加权平均,得到最终结果

2.7 调优提分过程

在具体比赛中,很多结果不是一蹴而就的,而是经过了多次调参的结果,在操作中,以下参数对结果影响较大:

  • 学习率大小
  • 思路中提到的阈值
  • 在调模型过程中,我仔细对比了数据,发现部分对于借贷而言是没有作用的,故删除,这一举措对线上分影响较大,我删去的特征有借贷具体的月、周、日,最早确立信贷的月份,邮编,地区等。当然具体问题具体分析,每道题都有不相关的特征,删除这些或有奇效。
  • Kfold折数,15折效果明显优于5折

2.8 其他工作

在比赛中,我们还做了许多其他方面的努力,但对于最终的结果并未产生足够的效果,列举为:

  • 我们发现,数据中有一些噪声,如借贷人最早确立信贷的时间,居然有2070年的,我们查看了测试集的分布,添加时间约束,将样本筛选时间在1996-2002之间,但却使得线上分下降
  • 我们做了一些新的特征,如,我们根据债务收入比和其借贷金额算出其工资等,但对于线上分的影响也是负面的
  • 我们尝试使用xgboost,catboost,随机森林等集成学习模型训练融合,但结果不尽人意

三、结语

感谢你能看到这里,希望我的经历能帮助到你。
竞赛新手,深知才疏学浅,如有错误之处欢迎评论区指出,在此不胜感激。

  • 7
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 11
    评论
【资源介绍】 基于python实现的银行个贷违约预测源码+项目说明+数据集.zip 该项目是个人毕设项目,答辩评审分达到95分,代码都经过调试测试,确保可以运行!欢迎下载使用,可用于小白学习、进阶。 该资源主要针对计算机、通信、人工智能、自动化等相关专业的学生、老师或从业者下载使用,亦可作为期末课程设计、课程大作业、毕业设计等。 项目整体具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现不同的功能。 欢迎下载交流,互相学习,共同进步! 背景 ``` 为进一步促进金融普惠的推广落地,金融机构需要服务许多新的客群。 银行作为对风险控制要求很高的行业,因为缺乏对新客群的了解, 对新的细分客群的风控处理往往成为金融普惠的重要阻碍。如何利用银行现有 信贷行为数据来服务新场景、新客群成了一个很有价值的研究方向, 迁移学习是其中一个重要手段。 ``` 任务描述 ``` 本赛题要求利用已有的与目标客群稍有差异的另一批信贷数据, 辅助目标业务风控模型的创建,两者数据集之间存在大量相同的字段和极少的共同用户。 此处希望大家可以利用迁移学习捕捉不同业务中用户基本信息与违约行为之间的关联, 帮助实现对新业务的用户违约预测。 ``` 数据描述 - 训练数据 - train_public.csv:个人贷款违约记录数据 测试数据 - test_public.csv:测试数据集 评价指标 使用ROC曲线下面积AUC(Area Under Curve)作为评价指标。AUC值越大,预测越准确。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

锌a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值