前言
本次是在阿里云天池的第一个竞赛《零基础入门金融风控-贷款违约预测》,赛题以金融风控中的个人信贷为背景,要求选手根据贷款申请人的数据信息预测其是否有违约的可能,以此判断是否通过此项贷款,这是一个典型的分类问题。
最后精度为0.7287。
这个比赛很有意义,主要是可以参考论坛中大牛写的文章,内容全面详细,跟着顺序做完会有很大收获。Datawhale零基础入门金融风控 Task1 赛题理解
1 数据分析+可视化
以前可视化我是用Excel加python画图实现的,现在有个巨无敌的库,巨无敌的可视化工具——pandas_profiling!!
import pandas_profiling
def profiling(train,test):
train_y0 = train[train['isDefault'] == 0]
train_y1 = train[train['isDefault'] == 1]
pfr_y1 = pandas_profiling.ProfileReport(train_y1)
pfr_y1.to_file("./train_y1.html")
pfr_y0 = pandas_profiling.ProfileReport(train_y0)
pfr_y0.to_file("./train_y0.html")
pfr = pandas_profiling.ProfileReport(train)
pfr.to_file("./train.html")
pfr_y = pandas_profiling.ProfileReport(test)
pfr_y.to_file("./test.html")
1.1 Overview
从Overview中,我们可以得知训练集有800000个,其中缺失值占据1.8%;其变量(包含预测值)有47个,数值型为36个,类别型为7个,布尔值为4个。
1.2 Warnings
Constant表示只有一个变量值;High cardinality是指高数量类别特征;High correlation是指高相似特征。
Missing表示缺失值。
Skewed表示偏态分布;Unique表示唯一值;Zeros表示变量值大多为0。
1.3 Variables
以loanAmnt为例,我们可以查看一个变量的各种统计,像最值、均值、中值、标准差等,当然还可以查看Common values和Extreme values这两类普遍值和极端值。
2 特征工程
将特征人为区分开来(因为有些数值特征实际上是无顺序的变量特征,如postCode,难以用代码区分)
numerrical = ['loanAmnt','interestRate','installment','annualIncome','dti',
'delinquency_2years','ficoRangeHigh','ficoRangeLow','openAcc',
'pubRec','pubRecBankruptcies','revolBal','revolUtil','totalAcc']
nominal = ['term','employmentTitle','homeOwnership','verificationStatus',
'purpose','postCode','regionCode','initialListStatus','applicationType',
'title','n0','n1','n2','n3','n4','n5','n6','n7','n8','n9','n10','n11','n12',
'n13','n14','id']
ordinal = ['grade','subGrade','employmentLength','earliesCreditLine','issueDate']
y = ['isDefault']
numerrical——表示数值特征
nominal——表示无顺序的类别特征
ordina——表示有顺序的类别特征
y——表示预测值。
2.1 提取新特征
①债权类——从annualIncome、installment、loanAmnt、annualIncome、dti几个财务类信息互相组合提取出新特征。
x['Income_installment']=round(x.loc[:,'annualIncome']/x.loc[:,'installment'],2)
x['loanAmnt_installment']=round(x.loc[:,'loanAmnt']/x.loc[:,'installment'],2)
x['debt']=round(x.loc[:,'annualIncome']*x.loc[:,'dti'],2)
x['loanAmnt_debt']=round(x.loc[:,'annualIncome']/x.loc[:,'debt'],2)
②fico——求fico的平均值。
x['fico']=(x.loc[:,'ficoRangeHigh']+x.loc[:,'ficoRangeLow'])*0.5
③employmentLength——提取出就业年限的数字(转换为连续变量)。
def employmentLength_to_int(s):
if pd.isnull(s):
return s
else:
return np.int8(s.split()[0])
x["employmentLength"].replace(to_replace="10+ years", value="10 years", inplace=True)
x["employmentLength"].replace(to_replace="< 1 year", value="0 years", inplace=True)
x['employmentLength'] = x.loc[:,"employmentLength"].apply(employmentLength_to_int)
④CreditLine——计算信用开户到本次借贷的时间,即信用账户的年限。
x['issueDate'] = x.loc[:,"issueDate"].apply(lambda s: int(s[:4]))
x['earliesCreditLine'] = x.loc[:,'earliesCreditLine'].apply(lambda s: int(s[-4:]))
x['CreditLine'] = x.loc[:,'earliesCreditLine'] - x.loc[:,'issueDate']
最后,增添新特征;根据之前Warnings,删除相似特征(High correlation)、唯一值(Unique)、单变量值(Constant),和以上用来生成新特征的旧特征。
numerrical=list(set(numerrical) - {'ficoRangeHigh', 'ficoRangeLow'}) +
['Income_installment','loanAmnt_installment','loanAmnt_debt','fico']
nominal=list(set(nominal)-{'id','n10', 'n2'})
ordinal=list(set(ordinal) - {'grade', 'earliesCreditLine', 'issueDate'}) + ['CreditLine']
2.3 特征编码
在决定编码前我选择了XGB模型,所以按照模型去查询编码方式。
根据XGBoost之类别特征的处理和kaggle编码categorical feature总结两篇编码总结。
from category_encoders import WOEEncoder ,OneHotEncoder,CatBoostEncoder,TargetEncoder
def Category_Encoders(train_x, train_y, test_x, vel_x):
for col in nominal:
distinct = train_x[col].nunique()
if distinct < 4 and distinct >2:
enc = OneHotEncoder(handle_missing='indicator').fit(train_x[col], train_y)
elif distinct >= 4:
# enc = WOEEncoder().fit(train_x[col], train_y)
# enc = TargetEncoder().fit(train_x[col],train_y)
enc = CatBoostEncoder().fit(train_x[col],train_y)
train_x[col] = enc.transform(train_x[col])
test_x[col] = enc.transform(test_x[col])
vel_x[col] = enc.transform(vel_x[col])
return train_x, test_x, vel_x
2.4 缺失值处理和分箱处理
暂不处理,将缺失值视为一种信息,交给xgb模型处理。
分箱暂且没想到好的分箱方法,也交给xgb模型处理。
3 训练模型
模型方面自然是选择了百试百灵的XGBClassifier模型
3.1 模型调参
当年GridSearchCV用的贼爽,但当我用到这个80w大数据集时候,简直不要太慢了!!
总之,当需要调很多参数或是数据集很大的时候,欢迎使用贝叶斯优化调参示例代码 (xgboost,lgbm)
def BO_xgb(x,y):
t1=time.clock()
def xgb_cv(max_depth,gamma,min_child_weight,max_delta_step,subsample,colsample_bytree):
paramt={'booster': 'gbtree',
'max_depth': int(max_depth),
'gamma': gamma,
'eta': 0.1,
'objective': 'binary:logistic',
'nthread': 4,
'eval_metric': 'auc',
'subsample': max(min(subsample, 1), 0),
'colsample_bytree': max(min(colsample_bytree, 1), 0),
'min_child_weight': min_child_weight,
'max_delta_step': int(max_delta_step),
'seed': 1001}
model=XGBClassifier(**paramt)
res = cross_val_score(model,x, y, scoring='roc_auc', cv=5).mean()
return res
cv_params ={'max_depth': (5, 12),
'gamma': (0.001, 10.0),
'min_child_weight': (0, 20),
'max_delta_step': (0, 10),
'subsample': (0.4, 1.0),
'colsample_bytree': (0.4, 1.0)}
xgb_op = BayesianOptimization(xgb_cv,cv_params)
xgb_op.maximize(n_iter=20)
print(xgb_op.max)
t2=time.clock()
print('耗时:',(t2-t1))
return xgb_op.max
我们对'max_depth','gamma','min_child_weight','max_delta_step','subsample','colsample_bytree'六个参数进行调参,并最后赋予'n_estimators':1000,'learning_rate':0.02。
最终最佳参数为:
'booster': 'gbtree','eta': 0.1,'nthread': 4,'eval_metric': 'auc','objective': 'binary:logistic',
'colsample_bytree': 0.4354, 'gamma': 9.888, 'max_delta_step': 4,'n_estimators':1000,'learning_rate':0.02,
'max_depth': 10, 'min_child_weight': 3.268, 'subsample': 0.7157
3.2 ROC可视化
分别look下预测集和训练集的ROC。
def roc(m,x,y,name):
y_pred = m.predict_proba(x)[:,1]
""""预测并计算roc的相关指标"""
fpr, tpr, threshold = metrics.roc_curve(y, y_pred)
roc_auc = metrics.auc(fpr, tpr)
print(name+'AUC:{}'.format(roc_auc))
"""画出roc曲线图"""
plt.figure(figsize=(8, 8))
plt.title(name)
plt.plot(fpr, tpr, 'b', label = name + 'AUC = %0.4f' % roc_auc)
plt.ylim(0,1)
plt.xlim(0,1)
plt.legend(loc='best')
plt.title('ROC')
plt.ylabel('True Positive Rate')
plt.xlabel('False Positive Rate')
# 画出对角线
plt.plot([0,1],[0,1],'r--')
plt.show()
3 提交成绩
def prediction(m,x):
submit=pd.read_csv('sample_submit.csv')
y_pred = m.predict_proba(x)[:,1]
submit['isDefault'] = y_pred
submit.to_csv('prediction.csv', index=False)
最终成绩roc=0.7287,排名357。
小结
作为一名信用管理专业的学生,来到天池做这个贷款违约预测,也算和本专业结合了。
这次最大困难我觉得是调参的不利,对于这种大数据处理,模型调参实在是太慢了。我之前习惯于特征改进一步就尝试调参优化,现在即使是使用贝叶斯调参,也是需要1小时以上的时间,并且还是在参数n_estimators默认100的情况下(n_estimators越大耗时越长)。
最后,此模型应该还有调参优化的可能,需要我再去求学。