前几篇博文中,我们对金融数据进行了分析,数据预处理和特征工程。这篇博文将利用金融数据训练出一个GBDT模型。
本篇博文的主要内容分为以下三个部分:
- GBDT模型简介
- 分类器性能指标
- GBDT在流失预警模型中的应用
GBDT模型简介
有关GBDT模型的介绍,大家可以看我的另外两篇博文机器学习–>集成学习–>Bagging,Boosting,Stacking,机器学习–>集成学习–>GBDT,RandomForest里面关于GBDT的相关内容。
GBDT模型参数问题,这里我们以sklearn里面的GBDT为例来说,打开网址sklearn.ensemble.GradientBoostingClassifier。这里我们不关注GBDT里面的所有参数意义,只解释下在对金融数据建模调参时最常用的一些参数意义:
GBDT框架的参数
n_estimators: 分类树的个数,即K
learning_rate: 即每个弱学习器的权重缩减系数ν,也称作步长。较小的ν意味着需要更多
的弱学习器的迭代次数。参数n_estimators和learning_rate要一起调参。可以从一个小一点
的ν开始调参,默认是1
Subsample: (不放回)抽样率,推荐在[0.5, 0.8]之间,默认是1.0,即不使用子采样
init: 即初始化的时候的弱学习器,一般用在对数据有先验知识,或者之前做过一些拟合的
时候
loss: 即GBDT算法中的损失函数
弱分类树的参数
max_features: 划分时考虑的最大特征数
max_depth: 决策树最大深度
min_samples_split:内部节点再划分所需最小样本数。默认是2.如果样本量不大,不需要管
这个值。如果样本量数量级非常大,则推荐增大这个值
min_samples_leaf: 叶子节点最少样本数
min_weight_fraction_leaf:叶子节点最小的样本权重。默认是0,就是不考虑权重问题。
一般来说,如果我们有较多样本有缺失值,或者分类树样本的分布类别偏差很大,就会引
入样本权重,这时我们就要注意这个值了
max_leaf_nodes: 最大叶子节点数,通过限制最大叶子节点数,可以防止过拟合
min_impurity_split: 节点划分最小不纯度
有关更多GBDT的参数含义说明请参看我另外一篇博文
机器学习–>集成学习–>BGM调参
分类器性能指标简介
表示分类正确:
- True Positive:本来是正样例,分类成正样例。
- True Negative:本来是负样例,分类成负样例。
表示分类错误:
- False Positive :本来是负样例,分类成正样例,通常叫误报。
- False Negative:本来是正样例,分类成负样例,通常叫漏报。
准确度
真正类率(True Postive Rate)TPR: TP/(TP+FN),代表分类器预测的正类中实际正实例占
所有正实例的比例。Sensitivity
负正类率(False Postive Rate)FPR: FP/(FP+TN),代表分类器预测的正类中实际负实例
占所有负实例的比例。1-Specificity
真负类率(True Negative Rate)TNR: TN/(FP+TN),代表分类器预测的负类中实际负实例
占所有负实例的比例,TNR=1-FPR。Specificity
真正类率(True Postive Rate)TPR就是查全率
分类器给出针对每个实例为正类的概率,那么通过设定一个阈值如0.6,概率大于等于0.6的为正类,小于0.6的为负类。对应的就可以算出一组(FPR,TPR),在平面中得到对应坐标点。随着阈值的逐渐减小,越来越多的实例被划分为正类,但是这些正类中同样也掺杂着真正的负实例,即TPR和FPR会同时增大。阈值最大时,对应坐标点为(0,0),阈值最小时,对应坐标点(1,1)。
AUC是图中曲线下方的面积,值越大,分类效果越佳
通常情况下AUC越大学习器的效果越好。,即若一个学习器的ROC曲线被另外一个学习器曲线完全包住,那么可以断言,后一个学习器的性能优于前者。如果发生交叉则难以比较,如果非要比较,比较合理的判断是比较ROC下的面积即AUC大小。
GBDT在流失预警模型中的应用
使用默认参数,在训练集上
from sklearn.model_selection import train_test_split
from sklearn import ensemble,cross_validation, metrics
X_train, X_test, y_train, y_test = train_test_split(modelData[allFeatures],modelData['CHURN_CUST_IND'], test_size=0.5,random_state=9)y_train.value_counts()#try 1: using default parameter
gbm0 = GradientBoostingClassifier(random_state=10)
gbm0.fit(X_train,y_train)
y_pred = gbm0.predict(X_test)
y_predprob = gbm0.predict_proba(X_test)[:,1]##输出所有样本属于0和1的概率,这里选择输出样本属于1的概率
print "Accuracy : %.4g" % metrics.accuracy_score(y_test, y_pred)
print "AUC Score (Testing): %f" % metrics.roc_auc_score(y_test, y_predprob)y_pred2 = gbm0.predict(X_train)
y_predprob2 = gbm0.predict_proba(X_train)[:,1]
print "Accuracy : %.4g" % metrics.accuracy_score(y_train, y_pred2)
print "AUC Score (Testing): %f" % metrics.roc_auc_score(y_train, y_predprob2)
都还不错。但是能不能更好点?
首先我们从步长(learning rate)和迭代次数(n_estimators)入手。一般来说,开始选择一个较小的步长来网格搜索最好的迭代次数。这里,我们将步长初始值设置为0.1,迭代次数的搜索范围是20~80
#tunning the number of estimators
param_test1 = {'n_estimators':range(20,81,10)}
gsearch1 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, min_samples_split=300,min_samples_leaf=20,max_depth=8,max_features='sqrt', subsample=0.8,random_state=10),param_grid = param_test1, scoring='roc_auc',iid=False,cv=5)
gsearch1.fit(X_train,y_train)
gsearch1.grid_scores_, gsearch1.best_params_, gsearch1.best_score_
最好的迭代次数是70,对应的score是85.10%。
好像比默认参数的效果差。。。。
找到了一个合适的迭代次数,现在我们开始对决策树进行调参。首先我们对决策树最大深度max_depth和内部节点再划分所需最小样本样min_samples_split进行网格搜索。搜索的范围分别是3~13和 100~800
#tunning the parameters of simple trees
param_test2 = {'max_depth':range(3,14,2), 'min_samples_split':range(100,801,200)}
gsearch2 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70, min_samples_leaf=20,max_features='sqrt', subsample=0.8, random_state=10),param_grid = param_test2, scoring='roc_auc',iid=False, cv=5)
gsearch2.fit(X_train,y_train)
gsearch2.grid_scores_, gsearch2.best_params_, gsearch2.best_score_
最佳的最大深度和最小样本数分别是9和500,对应的score是85.36%
由于决策树深度9是一个比较合理的值,我们把它定下来,对于内部节点再划分所需最小样本数min_samples_split,我们暂时不能一起定下来,因为这个还和决策树其他的参数存在关联。下面我们再对内部节点再划分所需最小样本数min_samples_split和叶子节点最少样本数min_samples_leaf一起调参。调整范围分别是4001000,以及60100。
param_test3 = {'min_samples_split':range(400,1001,100), 'min_samples_leaf':range(60,101,10)}
gsearch3 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70,max_depth=9,max_features='sqrt', subsample=0.8, random_state=10),param_grid = param_test3, scoring='roc_auc',iid=False, cv=5)
gsearch3.fit(X_train,y_train)
gsearch3.grid_scores_, gsearch3.best_params_, gsearch3.best_score_
最佳的最小样本数和叶节点最小样本数分别是500和70,对应的score是85.54%
现在我们再对最大特征数max_features进行网格搜索, 范围从5 到25,最佳值是25.
BUT !
对于边界值,通常还要再放大范围。我们将范围扩大到30,最佳值是28.
再对子采样的比例进行网格搜索,范围从0.6到0.9, 最佳值是0.8.
现在我们基本已经得到我们所有调优的参数结果了。这时我们可以减半步长,最大迭代次数加倍来增加我们模型的泛化能力。再次拟合我们的模型,得到的最优步长是0.05,最大迭代次数是1000,在训练集和测试集上的表现是:
### tunning max_features
param_test4 = {'max_features':range(5,31,2)}
gsearch4 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70,max_depth=9, min_samples_leaf =70,min_samples_split =500, subsample=0.8, random_state=10),param_grid = param_test4, scoring='roc_auc',iid=False, cv=5)
gsearch4.fit(X_train,y_train)
gsearch4.grid_scores_, gsearch4.best_params_, gsearch4.best_score_## tunning subsample
param_test5 = {'subsample':[0.6,0.7,0.75,0.8,0.85,0.9]}
gsearch5 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.1, n_estimators=70,max_depth=9, min_samples_leaf =70,min_samples_split =500, max_features=28, random_state=10),param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
gsearch5.fit(X_train,y_train)
gsearch5.grid_scores_, gsearch5.best_params_, gsearch5.best_score_# tunning the learning rate and
gbm2 = GridSearchCV(estimator = GradientBoostingClassifier(learning_rate=0.05, n_estimators=70,max_depth=9, min_samples_leaf =70,min_samples_split =1000, max_features=28, random_state=10,subsample=0.8),param_grid = param_test5, scoring='roc_auc',iid=False, cv=5)
gbm2.fit(X_train,y_train)y_pred1 = gbm2.predict(X_train)
y_predprob1= gbm2.predict_proba(X_train)[:,1]
print "Accuracy : %.4g" % metrics.accuracy_score(y_train, y_pred1)
print "AUC Score (Train): %f" % metrics.roc_auc_score(y_train, y_predprob1)y_pred2 = gbm2.predict(X_test)
y_predprob2= gbm2.predict_proba(X_test)[:,1]
print "Accuracy : %.4g" % metrics.accuracy_score(y_test, y_pred2)
print "AUC Score (Train): %f" % metrics.roc_auc_score(y_test, y_predprob2)