前言:去年参加了数据城堡的算法竞赛,一直没时间记录下来,趁今天来梳理下这个竞赛项目的方方面面。赛题为用户贷款风险预测,目标是利用用户基本信息、用户银行流水、用户信用卡账单以及用户浏览行为4个表的数据预测用户贷款后逾期的概率,其中带标签数据55596条,无标签数据13899条,个人最好成绩是排名前8%。
解决方案概述
此次大赛目标是从用户行为数据分析借款用户的信用状况,来判断其是否逾期。针对需要解决的问题和数据特征,主要从三个方面进行处理:数据预处理,特征工程,模型训练。
首先,由于数据中存在缺失值,因此需要对缺失值数据进行预处理。其次,采用基于学习模型的特征排序方法做了特征选择。然后,针对类别不平衡问题,主要是对少量样本过采样,针对过程中出现的过拟合问题,采用了pca降维以及对特征进行选择的方法。
本文框架如下:
- 好坏样本定义说明
- 样本概述
- 缺失值处理
- 构建新特征
- 特征选择
- 模型
- 最终结果
1.好坏样本定义
样本有55596条带标签数据,其中标签为0,1,1表示用户逾期。
正负样本分布如下:
print('训练集中各类别数据的个数:', trains.groupby('标签').size())
训练集中各类数据的个数: 标签
0.0 48413
1.0 7183
可以看出正负样本并不平衡,正样本大概是负样本的7倍,因此存在一个样本不平衡问题。
2.样本概述
提供的近7w条数据中,主要为四个表,分别是用户信息表,银行流水记录,用户浏览行为,信用卡账单。其中字段名如下:
用户信息表:
用户id | 性别 | 职业 | 教育程度 | 婚姻状态 | 户口类型 |
---|
银行流水记录表:
用户id | 时间戳 | 交易类型 | 交易金额 | 工资收入标记 |
---|
用户浏览行为表:
用户id | 时间戳 | 浏览行为数据 | 浏览子行为编号 |
---|
信用卡账单表:
用户id | 时间 | 银行标识 | 上期账单金额 | 上期还款金额 |
---|---|---|---|---|
调整金额 | 循环利息 | 可用余额 | 预借现金额度 | 还款状态 |
信用卡额度 | 本期账单余额 | 本期账单最低还款额 | 消费笔数 | 本期账单金额 |
共计27个字段。字段数据都经过举办方脱敏处理,业务信息缺失。
3.缺失值处理
赛题数据中大部分样本都有缺失值,常用的缺失值处理方法是缺失值填充(用同类别数据的特征均值,中值等)
feature=dataset[:]
dataset=dataset.fillna(-1)
d=feature['用户银行流水记录缺失统计']=(dataset==-1).sum(axis=1)
用均值填充缺失值
feature.fillna(feature.mean(),inplace=True)
4.构建新特征
赛题数据含有类别特征,很多算法(如逻辑回归,SVM)只能处理数值型特征,这种情况下需要对类别特征进行编码,这里采用了 One-Hot 编码,得到了 01 特征,解决了分类器不能处理类别特征的问题。
dataset=pd.get_dummies(dataset,
columns=dataset[['用户性别','用户职业','用户教育程度',
'用户婚姻状态','用户户口类型']]).drop(['标签'],axis=1)
根据放款时间来划分时间窗口,构建每个表的放款前特征和放款后特征。
# ----------------------------------------银行流水特征------------------------------------------#
print('银行流水记录')
feature = pd.read_csv('../feature/训练放款时间表')
d = pd.read_csv('../feature/银行流水记录表')
d=pd.merge(d,feature,how='left', on = '用户标识')
# ----------------------------------------放款前特征统计------------------------------------------#
print('放款前特征统计')
t = d[(d['流水时间'] <= d['放款时间'])]
gb1 = t[(t['交易类型'] == 0)].groupby(['用户标识'], as_index=False) # 收入统计
gb2 = t[(t['交易类型'] == 1)].groupby(['用户标识'], as_index=False) # 支出统计
gb3 = t[(t['工资收入标记'] == 1)].groupby(['用户标识'], as_index=False) # 工资收入统计
x1 = gb1['交易金额'].agg({'放款前用户收入笔数': 'count', '放款前用户收入总计': 'sum'})
x2 = gb2['交易金额'].agg({'放款前用户支出笔数': 'count', '放款前用户支出总计': 'sum'})
x3 = gb3['交易金额'].agg({'放款前用户工资收入笔数': 'count', '放款前用户工资收入总计': 'sum'})
feature = pd.merge(feature, x1, how='left', on='用户标识')
feature = pd.merge(feature, x2, how='left', on='用户标识')
feature = pd.merge(feature, x3, how='left', on='用户标识')
feature['放款前用户收入支出笔数差值'] = feature['放款前用户收入笔数'] - feature['放款前用户支出笔数']
feature['放款前用户收入支出总计差值'] = feature['放款前用户收入总计'] - feature['放款前用户支出总计']
feature['放款前用户非工资收入笔数'] = feature['放款前用户收入笔数'] - feature['放款前用户工资收入笔数']
feature['放款前用户非工资收入总计'] = feature['放款前用户收入总计'] - feature['放款前用户工资收入总计']
构建新特征后特征维度达到164维。
5.特征选择
构建特征后,特征维度达到164维,多维特征一方面可能会导致维数灾难,另一方面很容易导致过拟合,因此需要做降维处理,常见的降维方法有 PCA。除了采用降维算法之外,也可以用特征选择来降低特征维度。特征选择的方法很多:卡方检验、皮尔森相关系数、正则化方法(L1, L2)、基于模型的特征选择方法。
# 特征选择,基于卡方检验
# trains=SelectKBest(chi2,k=20).fit_transform(trains,target)
# 基于惩罚项的特征选择法
# trains=SelectFromModel(LogisticRegression(penalty='l1',C=0.1)).fit_transform(trains,target)
# 基于树模型的特征选择
# trains=SelectFromModel(GradientBoostingClassifier()).fit_transform(trains,target)
# 降维,基于pca
pca=PCA(n_components=50)
trains=pca.fit_transform(trains)
test=pca.fit_transform(test)
6.模型
这里主要尝试了LR和XGB,在效果上XGB更好,可能是因为XGB在训练的同时会进行特征选择。
parameters= [{
'max_depth':[3,5,7], ##5)
'learning_rate':[0.1,0.5, 1.0],#0.1
'subsample':[0.75,0.8,0.85,0.9],#0.8
'min_child_weight':[1,3,5]#5
}]
#parameters= [{'n_estimators':[100,200,500,1000]
# }]
clf = GridSearchCV(xgb.XGBClassifier(n_estimators=100,gamma=0,scale_pos_weight=1),
param_grid=parameters,scoring='roc_auc',n_jobs=4,iid=False,cv=5)
print('开始训练')
clf.fit(x_train, y_train)
参数解释:
learning_rate:学习速率
min_child_weight :这个参数用来控制过拟合,如果数值太大可能会导致欠拟合。
max_depth:设置树的最大深度,控制过拟合,如果树的深度太大会导致过拟合
subsample:对原数据集进行随机采样来构建单个树。这个参数代表了在构建树时候对原数据集采样的百分比。eg:如果设为0.8表示随机抽取样本中80%的个体来构建树
scale_pos_weight:在样本类别十分不平衡时,参数设定为一个正值,可以使算法更快收敛
模型结果:
AUC:0.87
特征重要性输出:
image.png可见最重要特征有用户性别、用户职业、用户婚姻状态、用户教育程度、用户户口类型、放款前浏览行为数据、放款前浏览行为数据最小值、放款前浏览子行为编号_8
可见除了基本信息外,用户的浏览行为是强有力的特征。
7.最终结果
不同方法及模型线下表现效果:
预处理 | AUC(LR) | AUC(XGB) |
---|---|---|
标准化处理 | 0.8726 | 0.8722 |
特征选择(卡方检验) | 0.8742 | 0.8723 |
基于惩罚项的特征选择 | 0.8741 | 0.8723 |
基于树模型 | 0.8741 | 0.8711 |
构建新特征后:
预处理 | AUC(LR) | AUC(XGB) |
---|---|---|
构建放款前后新特征 | 0.8973 | |
优化用户特征 | 0.9172 |
最终结果以逾期概率的形式上传到平台:
userid,probability
55597,0.3506719172000885
55598,0.3657565116882324
55599,0.3827580213546753
55600,0.36820918321609497
55601,0.34563612937927246
55602,0.36067867279052734
55603,0.36357182264328003
55604,0.3907186985015869
55605,0.34469443559646606
55606,0.3836720585823059
55607,0.3370608389377594
55608,0.38630616664886475
55609,0.3718336224555969
提交结果
image.png
第一名成绩为0.4746,与之相比我还有很大差距,但经过这次比赛我学到了很多,主要是关于解决问题的思路,感谢诸位大神的博客,这次主要参考了微额借款用户人品预测大赛冠军的解决方案。
以上就是这次比赛的大概内容了!
网友评论