最近准备研究一下信贷风控中机器学习模型评分卡的制作。信贷评分卡分为两种,一种是用逻辑回归,称为评分卡;一种是用集成学习算法,称为机器学习模型。逻辑回归算法相对简单,但是解释性要求高;机器学习模型理论上效果要更好一点,但是无法解释,而且模型容易不稳定。于是找了一下网上能找到的关于机器学习模型做评分卡的案例,主要有拍拍贷比赛实例、金融风控实战、kaggle上的Home Credit Default Risk比赛,附上相应的课程或比赛链接。
- 拍拍贷比赛案例https://www.bilibili.com/video/BV1NE41157Ag?p=29
- 金融风控实战https://www.bilibili.com/video/BV18J411R7ei?p=11
- Kaggle案例https://www.kaggle.com/fanzzz/understand-variables-in-chinese
本篇文章是一篇简单的xgboost快速上手的教程,不涉及算法推导,帮助自己回顾一下xgboost的基本用法,后续会再复习一下算法的推导过程以及优缺点。
一、读取数据并指定参数建模
xgboost读取数据有两种方式:
- 使用xgboost自带的数据集格式 + xgboost自带的建模方式
把数据读取成xgb.DMatrix格式(libsvm/dataframe.values给定X和Y)
准备好一个watch_list(观测和评估的数据集)
xgb.train(dtrain)
xgb.predict(dtest)
- 使用pandas的DataFrame格式 + xgboost的sklearn接口
estimator = xgb.XGBClassifier()/xgb.XGBRegressor()
estimator.fit(df_train.values, df_target.values) 先看一下第一种方式读取数据和建模的方法。
importnumpyasnp
importpandasaspd
importpickle
importxgboostasxgb
fromsklearn.model_selectionimporttrain_test_split
data=pd.read_csv('./data/Pima-Indians-Diabetes.csv')
train,test=train_test_split(data)
#转换成Dmatrix格式
feature_columns=['Pregnancies','Glucose','BloodPressure','SkinThickness','Insulin','BMI','DiabetesPedigreeFunction','Age']
target_column='Outcome'
#需要将dataframe格式的数据转化为矩阵形式
xgtrain=xgb.DMatrix(train[feature_columns].values,train[target_column].values)
xgtest=xgb.DMatrix(test[feature_columns].values,test[target_column].values)
#参数设定
param={'max_depth':5,'eta':0.1,'silent':1,'subsample':0.7,'colsample_bytree':0.7,'objective':'binary:logistic'}
#设定watchlist用于查看模型状态
watchlist=[(xgtest,'eval'),(xgtrain,'train')]
num_round=10
bst=xgb.train(param,xgtrain,num_round,watchlist)
#使用模型预测
preds=bst.predict(xgtest)
#判断准确率
labels=xgtest.get_label()
print('错误类为%f'%\
(sum(1foriinrange(len(preds))ifint(preds[i]>0.5)!=labels[i])/float(len(preds))))
#模型存储
bst.save_model('./model/0002.model')

第一点就是输入数据形式要转化成矩阵的形式,第二点就是watchlist参数用于查看模型的状态,也就是为了输出eval-error和train-error。然后再解释下几个参数的含义:
'max_depth':设置树的最大深度。默认为6。 'eta':学习率。默认为0.3。 'silent':0表示输出信息, 1表示安静模式。默认为0。 'subsample':观测的子样本的比率,即对总体进行随机抽样的比例。默认为1。 'colsample_bytree ':用于构造每棵树时变量的子样本比率.即特征抽样。默认为1。 'objective':最小化的损失函数。
xgboost的参数可以分为三类,通用参数/general parameters, 集成(增强)参数/booster parameters 和 任务参数/task parameters。 以上silent是通用参数,objective是任务参数,其它的都是集成参数。

再来看一下使用sklearn接口进行建模的例子。
#!/usr/bin/python
importwarnings
warnings.filterwarnings("ignore")
importnumpyasnp
importpandasaspd
importpickle
importxgboostasxgb
fromsklearn.model_selectionimporttrain_test_split
fromsklearn.externalsimportjoblib
data=pd.read_csv('./data/Pima-Indians-Diabetes.csv')
train,test=train_test_split(data)
#取出特征X和目标y的部分
feature_columns=['Pregnancies','Glucose','BloodPressure','SkinThickness','Insulin','BMI','DiabetesPedigreeFunction','Age']
target_column='Outcome'
train_X=train[feature_columns].values
train_y=train[target_column].values
test_X=test[feature_columns].values
test_y=test[target_column].values
#初始化模型
xgb_classifier=xgb.XGBClassifier(n_estimators=20,max_depth=4,learning_rate=0.1,subsample=0.7,colsample_bytree=0.7)
#拟合模型
xgb_classifier.fit(train_X,train_y)
#使用模型预测
preds=xgb_classifier.predict(test_X)
#判断准确率
print('错误类为%f'%((preds!=test_y).sum()/float(test_y.shape[0])))
#模型存储
joblib.dump(xgb_classifier,'./model/0003.model')
读取数据和建模的大致流程就这么两种,下面结合xgb建模的方式进行深入地了解。 利用xgb进行交叉验证。
param={'max_depth':5,'eta':0.1,'silent':0,'subsample':0.7,'colsample_bytree':0.7,'objective':'binary:logistic'}
num_round=10
dtrain=xgb.DMatrix(train[feature_columns].values,train[target_column].values)
xgb.cv(param,dtrain,num_round,nfold=5,metrics={'error'},seed=0)

xgb.cv的参数的含义如下:
'num_round':最大迭代次数。 'metric':评价指标,一般用AUC。
除了xgb自带的验证方法以外还有GridSearchCV交叉验证方法,后面会提到。然后进行添加预处理的交叉验证,即通过计算正负样本比调整样本的权重。
#计算正负样本比,调整样本权重
deffpreproc(dtrain,dtest,param):
label=dtrain.get_label()
ratio=float(np.sum(label==0))/np.sum(label==1)
param['scale_pos_weight']=ratio
return(dtrain,dtest,param)
#先做预处理,计算样本权重,再做交叉验证
xgb.cv(param,dtrain,num_round,nfold=5,
metrics={'auc'},seed=0,fpreproc=fpreproc)
在参数里面加了一个'scale_pos_weight',可以在样本类别不平衡的时候加速收敛。 下面再进行自定义损失函数与评估准则,这也是xgb的优势所在。
print('runningcrossvalidation,withcutomsizedlossfunction')
#自定义损失函数,需要提供损失函数的一阶导和二阶导
deflogregobj(preds,dtrain):
labels=dtrain.get_label()
preds=1.0/(1.0+np.exp(-preds))
grad=preds-labels
hess=preds*(1.0-preds)
returngrad,hess
#自定义评估准则,评估预估值和标准答案之间的差距
defevalerror(preds,dtrain):
labels=dtrain.get_label()
return'error',float(sum(labels!=(preds>0.0)))/len(labels)
watchlist=[(dtest,'eval'),(dtrain,'train')]
param={'max_depth':3,'eta':0.1,'silent':1}
num_round=5
#自定义损失函数训练
bst=xgb.train(param,dtrain,num_round,watchlist,logregobj,evalerror)
#交叉验证
xgb.cv(param,dtrain,num_round,nfold=5,seed=0,
obj=logregobj,feval=evalerror)
针对业务改写评价函数,这里的要求是要保证损失函数二阶可导,原因只要推导一遍xgboost公式就理解了,因为其中有一步用到泰勒展开的二阶项。 此外,xgb还可以只用前n棵树进行预测,用到的参数是ntree_limit,不再赘述。
了解完xgb进行建模之后,再看一下使用sklearn进行xgb建模的实例。这里使用了鸢尾花数据集合波士顿房价预测数据集分别进行分类和回归的学习。
importpickle
importxgboostasxgb
importnumpyasnp
fromsklearn.model_selectionimportKFold,train_test_split,GridSearchCV
fromsklearn.metricsimportconfusion_matrix,mean_squared_error
fromsklearn.datasetsimportload_iris,load_digits,load_boston
rng=np.random.RandomState(31337)
分类:
#二分类:混淆矩阵
print("数字0和1的二分类问题")
digits=load_digits(2)
y=digits['target']
X=digits['data']
kf=KFold(n_splits=2,shuffle=True,random_state=rng)
print("在2折数据上的交叉验证")
fortrain_index,test_indexinkf.split(X):
xgb_model=xgb.XGBClassifier().fit(X[train_index],y[train_index])
predictions=xgb_model.predict(X[test_index])
actuals=y[test_index]
print("混淆矩阵:")
print(confusion_matrix(actuals,predictions))
#多分类:混淆矩阵
print("\nIris:多分类")
iris=load_iris()
y=iris['target']
X=iris['data']
kf=KFold(n_splits=2,shuffle=True,random_state=rng)
print("在2折数据上的交叉验证")
fortrain_index,test_indexinkf.split(X):
xgb_model=xgb.XGBClassifier().fit(X[train_index],y[train_index])
predictions=xgb_model.predict(X[test_index])
actuals=y[test_index]
print("混淆矩阵:")
print(confusion_matrix(actuals,predictions))

回归:
#回归问题:MSE
print("\n波士顿房价回归预测问题")
boston=load_boston()
y=boston['target']
X=boston['data']
kf=KFold(n_splits=2,shuffle=True,random_state=rng)
print("在2折数据上的交叉验证")
fortrain_index,test_indexinkf.split(X):
xgb_model=xgb.XGBRegressor().fit(X[train_index],y[train_index])
predictions=xgb_model.predict(X[test_index])
actuals=y[test_index]
print("MSE:",mean_squared_error(actuals,predictions))

接下来看一下如何利用网格搜索查找最优超参数。这种方法仅适用于使用sklearn接口建模,采用GridSearchCV方法。
#调参方法:使用sklearn接口的regressor+GridSearchCV
print("参数最优化:")
y=boston['target']
X=boston['data']
xgb_model=xgb.XGBRegressor()
param_dict={'max_depth':[2,4,6],
'n_estimators':[50,100,200]}
clf=GridSearchCV(xgb_model,param_dict,verbose=1)
clf.fit(X,y)
print(clf.best_score_)
print(clf.best_params_)

可以看到网格搜索结果,最大深度为2,100个估计器。网格调参的方法就是将参数及参数的取值放入一个字典中,然后作为GridSearchCV这个方法的参数。 再看一下xgboost如何采用早停的参数停止树的增长。早停参数的调整适用于两种xgb建模方法。
#第1/2种训练方法的调参方法:earlystopping
X=digits['data']
y=digits['target']
X_train,X_val,y_train,y_val=train_test_split(X,y,random_state=0)
clf=xgb.XGBClassifier()
clf.fit(X_train,y_train,early_stopping_rounds=20,eval_metric="auc",
eval_set=[(X_val,y_val)])

该方法在训练集上学习模型,一颗一颗树添加,在验证集上看效果,当验证集效果不再提升,停止树的添加与生长。可以看到第10棵树时就不再提高,所以early_stopping_rounds的最佳值为10。关于xgboost调参的方法可以网上找一篇教程看一下,方法都是一样的,看一遍就懂了,附上很久之前整理的调参的基本思路。

最后再画图看一下特征的重要性。
iris=load_iris()
y=iris['target']
X=iris['data']
xgb_model=xgb.XGBClassifier().fit(X,y)
print('特征排序:')
feature_names=['sepal_length','sepal_width','petal_length','petal_width']
feature_importances=xgb_model.feature_importances_
indices=np.argsort(feature_importances)[::-1]
forindexinindices:
print("特征%s重要度为%f"%(feature_names[index],feature_importances[index]))
%matplotlibinline
importmatplotlib.pyplotasplt
plt.figure(figsize=(16,8))
plt.title("featureimportances")
plt.bar(range(len(feature_importances)),feature_importances[indices],color='b')
plt.xticks(range(len(feature_importances)),np.array(feature_names)[indices],color='b')
xgboost特征重要性指标: weight, gain, cover,可以通过xgb_model.get_booster().get_score(importance_type=importance_type))中的importance进行设置。 最后附上一个并行训练加速的代码,需要用到的时候再来看。
importos
if__name__=="__main__":
try:
frommultiprocessingimportset_start_method
exceptImportError:
raiseImportError("Unabletoimportmultiprocessing.set_start_method."
"ThisexampleonlyrunsonPython3.4")
#set_start_method("forkserver")
importnumpyasnp
fromsklearn.model_selectionimportGridSearchCV
fromsklearn.datasetsimportload_boston
importxgboostasxgb
rng=np.random.RandomState(31337)
print("ParallelParameteroptimization")
boston=load_boston()
os.environ["OMP_NUM_THREADS"]="2"#ortowhateveryouwant
y=boston['target']
X=boston['data']
xgb_model=xgb.XGBRegressor()
clf=GridSearchCV(xgb_model,{'max_depth':[2,4,6],
'n_estimators':[50,100,200]},verbose=1,
n_jobs=2)
clf.fit(X,y)
print(clf.best_score_)
print(clf.best_params_)
【作者】:Labryant
【原创公众号】:风控猎人
【简介】:某创业公司策略分析师,积极上进,努力提升。乾坤未定,你我都是黑马。
【转载说明】:转载请说明出处,谢谢合作!~