美文网首页
用AdaBoost和GBDT模型处理信用卡违约问题

用AdaBoost和GBDT模型处理信用卡违约问题

作者: apricoter | 来源:发表于2019-02-25 23:34 被阅读36次

    GBDT

    (Gradient Boosting Decision Tree梯度提升树) 又叫 MART(Multiple Additive Regression Tree),是一种迭代的决策树算法,该算法由多棵决策树组成,所有树的结论累加起来做最终答案。与其他有监督算法一样,可用于分类问题的识别和预测问题的解决。

    该集成算法体现了3方面的优势,分别是提升Boosting,梯度Gradient,和决策树Decision Tree。提升是指将多个弱分类器通过线下组合实现强分类器的过程,梯度是指算法在提升过程中求解损失函数时增强了灵活性和便捷性,决策树是指算法所使用的弱分类器为CART回归树。

    先讨论决策树,随机森林是利用Bootstrap抽样技术生成多个数据集,然后通过这些数据集构造多棵决策树,进而运用投票或平均的思想实现分类和预测问题的解决,但是这样的随机性会导致树与树之间并没有太多的相关性,往往会导致随机森林算法在拟合效果上不好,于是有了“提升”的概念,即通过改变样本点的权值和各个弱分类器的权重,将这些弱分类器组合,实现预测准确性的突破,然后又为了求解损失函数容易和方便,又提出了GBDT。

    GBDT的核心在于累加所有树的结果作为最终结果,回归树(预测实数值)是可以累加的,而分类树(分类标签值)是没办法累加的,所以GBDT中的树都是回归树,不是分类树,尽管GBDT调整后也可用于分类但不代表GBDT的树是分类树。

    以年龄为例:
    回归树在每个节点(不一定是叶子节点)都会得一个预测值,该预测值等于属于这个节点的所有人年龄的平均值。分枝时穷举每一个feature的每个阈值找最好的分割点,但衡量最好的标准不再是最大熵,而是最小化均方差--即(每个人的年龄-预测年龄)^2 的总和 / N,或者说是每个人的预测误差平方和 除以 N。这很好理解,被预测出错的人数越多,错的越离谱,均方差就越大,通过最小化均方差能够找到最靠谱的分枝依据。分枝直到每个叶子节点上人的年龄都唯一或者达到预设的终止条件(如叶子个数上限),若最终叶子节点上人的年龄不唯一,则以该节点上所有人的平均年龄做为该叶子节点的预测年龄。

    Boosting,迭代,即通过迭代多棵树来共同决策。GBDT是把所有树的结论累加起来做最终结论的,每棵树的结论并不是年龄本身,而是年龄的一个累加量。GBDT的核心就在于,每一棵树学的是之前所有树结论和的残差,这个残差就是一个加预测值后能得真实值的累加量。比如A的真实年龄是18岁,但第一棵树的预测年龄是12岁,差了6岁,即残差为6岁。那么在第二棵树里我们把A的年龄设为6岁去学习,如果第二棵树真的能把A分到6岁的叶子节点,那累加两棵树的结论就是A的真实年龄;如果第二棵树的结论是5岁,则A仍然存在1岁的残差,第三棵树里A的年龄就变成1岁,继续学。

    是boosting,但不是Adaboost。GBDT不是Adaboost Decistion Tree。就像提到决策树大家会想起C4.5,提到boost多数人也会想到Adaboost。Adaboost是另一种boost方法,它按分类对错,分配不同的weight,计算cost function时使用这些weight,从而让“错分的样本权重越来越大,使它们更被重视”。Bootstrap也有类似思想,它在每一步迭代时不改变模型本身,也不计算残差,而是从N个样本训练集中按一定概率重新抽取N个样本出来(单个样本可以被重复抽样),对这N个新的样本再训练一轮。由于数据集变了迭代模型训练结果也不一样,而一个样本被前面分错的越厉害,它的概率就被设的越高,这样就能同样达到逐步关注被分错的样本,逐步完善的效果。Adaboost的方法被实践证明是一种很好的防止过拟合的方法。Adaboost是一种最具代表的提升树。Adaboost也可以用于分类或者回归。

    GBDT是提升算法的扩展板,在原始的提升算法中,如果损失函数为平方损失或指数损失,求解损失函数的最小值问题会很简单,但如果损失函数为更一般的函数(比如绝对值损失函数获Huber损失函数),目标值的求解会复杂,Freidman提出了梯度提升算法,即在第m轮基础模型中,利用损失函数的负梯度值作为该轮基础模型损失值的近似,并利用这个近似值构建下一轮基础模型。

    优点:
    参数少,准确率高,运算时间少,对异常数据稳定。

    AdaBoost

    通过组合多个分类器(可以不同)的分类结果,获得了比简单的分类器更好的效果。选择不同的分类器可以缓解同一分类器可能放大的过拟合问题。

    有三种集成方法:Bagging、Boosting 和 Random Forset。Bagging通过随机抽样 S 次(有放回的抽样),得到 S 个与原数据集大小相同的数据集,作用到 S 个分类器上,最后根据投票决定分到哪一个类;Boosting 在 Bagging 上更进一步,它在数据集上顺序应用了多个不同的分类器。

    Boosting 中最流行的的一个算法是 AdaBoost,是一种迭代算法,其核心思想是针对同一个训练集训练不同的分类器(弱分类器),以弱学习器作为基分类器,并且输入数据,使其通过权重向量进行加权。在第一次迭代中,所有数据等权重,在后续迭代中,前次迭代中分错的数据的权值增大,将修改过权值的新数据集送给下层分类器进行训练,最后将每次训练得到的分类器最后融合起来,作为最后的决策分类器。这种针对错误的调节能力正是 AdaBoost 的长处。

    优点:
    很好的利用了弱分类器进行级联;
    可以将不同的分类算法作为弱分类器;
    AdaBoost 具有很高的精度;
    相对于 Bagging 算法和 Random Forest 算法,AdaBoost 充分考虑的每个分类器的权重;
    泛化错误率低,易编码,可以应用在大部分分类器上,无参数调整。

    缺点:
    AdaBoost 迭代次数也就是弱分类器数目不太好设定,可以使用交叉验证来进行确定;
    数据不平衡导致分类精度下降;
    训练比较耗时,每次重新选择当前分类器最好切分点;
    对离散点敏感。

    应用领域:
    模式识别、计算机视觉领域,用于二分类和多分类场景。

    # 导入第三方包
    import pandas as pd
    import matplotlib.pyplot as plt
    
    # 读入数据
    default = pd.read_excel(r'F:\default.xls')
    default.head()
    


    自变量包括客户的性别、受教育水平、年龄、婚姻状况、信用额度、6个月的历史还款状态、账单金额以及还款金额,因变量y表示用户在下个月的信用卡还款是否存在违约的情况(1表示违约,9表示不违约)

    首先查看因变量中各类别的比例差异,通过饼图:

    # 数据集中是否违约的客户比例
    # 为确保绘制的饼图为圆形,需执行如下代码
    plt.axes(aspect = 'equal')
    # 中文乱码和坐标轴负号的处理
    plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
    plt.rcParams['axes.unicode_minus'] = False
    #重命名因变量
    default.rename(columns={'default payment next month':'y'},inplace=True)
    # 统计客户是否违约的频数
    counts = default.y.value_counts()
    # 绘制饼图
    plt.pie(x = counts, # 绘图数据
            labels=pd.Series(counts.index).map({0:'不违约',1:'违约'}), # 添加文字标签
            autopct='%.1f%%' # 设置百分比的格式,这里保留一位小数
           )
    # 显示图形
    plt.show()
    

    违约客户比例占比22.1%,不违约客户占比77.9%,总体来说,两个类别的比例不算失衡。

    一般而言,如果两个类别比例为9:1,则认为失衡,为99:1,认为严重失衡。

    拆分数据

    # 将数据集拆分为训练集和测试集
    # 导入第三方包
    from sklearn import model_selection
    from sklearn import ensemble
    from sklearn import metrics
    
    # 排除数据集中的ID变量和因变量,剩余的数据用作自变量X
    X = default.drop(['ID','y'], axis = 1)
    y = default.y
    # 数据拆分
    X_train,X_test,y_train,y_test = model_selection.train_test_split(X,y,test_size = 0.25, random_state = 1234)
    

    构建AdaBoost模型

    # 构建AdaBoost算法的类
    AdaBoost1 = ensemble.AdaBoostClassifier()
    # 算法在训练数据集上的拟合
    AdaBoost1.fit(X_train,y_train)
    # 算法在测试数据集上的预测
    pred1 = AdaBoost1.predict(X_test)
    
    # 返回模型的预测效果
    print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred1))
    print('模型的评估报告:\n',metrics.classification_report(y_test, pred1))
    

    使用模型默认参数,准确率为81.25%,预测客户违约(y=1)的精确率为68%,覆盖率为32%,绘制ROC曲线

    # 计算客户违约的概率值,用于生成ROC曲线的数据
    y_score = AdaBoost1.predict_proba(X_test)[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
    # 计算AUC的值
    roc_auc = metrics.auc(fpr,tpr)
    
    # 绘制面积图
    plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
    # 添加边际线
    plt.plot(fpr, tpr, color='black', lw = 1)
    # 添加对角线
    plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
    # 添加文本信息
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
    # 添加x轴与y轴标签
    plt.xlabel('1-Specificity')
    plt.ylabel('Sensitivity')
    # 显示图形
    plt.show()
    

    面积AUC为0.78,不到0.8,通过调整参数,即交叉验证的方法来选择相对合理的参数值,并且可以进一步做特征筛选(按照重要因素)

    # 自变量的重要性排序
    importance = pd.Series(AdaBoost1.feature_importances_, index = X.columns)
    importance.sort_values().plot(kind = 'barh')
    plt.show()
    

    取出重要性比较高的变量再利用交叉验证选择参数建模

    importance[importance>0.02]
    
    importance[importance>0.02].index
    
    # 取出重要性比较高的自变量建模
    predictors = list(importance[importance>0.02].index)
    predictors
    

    先对基础模型决策树DecisionTreeClassifier的参数进行调优

    # 通过网格搜索法选择基础模型所对应的合理参数组合
    # 导入第三方包
    from sklearn.model_selection import GridSearchCV
    from sklearn.tree import DecisionTreeClassifier
    
    max_depth = [3,4,5,6]
    params1 = {'base_estimator__max_depth':max_depth}
    base_model = GridSearchCV(estimator = ensemble.AdaBoostClassifier(base_estimator = DecisionTreeClassifier()),
                              param_grid= params1, scoring = 'roc_auc', cv = 5, n_jobs = 4, verbose = 1)
    base_model.fit(X_train[predictors],y_train)
    # 返回参数的最佳组合和对应AUC值
    base_model.best_params_, base_model.best_score_
    

    经过5重交叉验证,最大的树深度选择为3

    再对提升树AdaBoostClassifier模型的参数调优

    # 通过网格搜索法选择提升树的合理参数组合
    # 导入第三方包
    from sklearn.model_selection import GridSearchCV
    
    n_estimators = [100,200,300]
    learning_rate = [0.01,0.05,0.1,0.2]
    params2 = {'n_estimators':n_estimators,'learning_rate':learning_rate}
    adaboost = GridSearchCV(estimator = ensemble.AdaBoostClassifier(base_estimator = DecisionTreeClassifier(max_depth = 3)),
                            param_grid= params2, scoring = 'roc_auc', cv = 5, n_jobs = 4, verbose = 1)
    adaboost.fit(X_train[predictors] ,y_train)
    # 返回参数的最佳组合和对应AUC值
    adaboost.best_params_, adaboost.best_score_
    

    经过5重交叉验证,AdaBoost算法的最佳基础模型个数为300,学习率为0..01

    基于以上调参结果重新构造模型

    # 使用最佳的参数组合构建AdaBoost模型
    AdaBoost2 = ensemble.AdaBoostClassifier(base_estimator = DecisionTreeClassifier(max_depth = 3),
                                           n_estimators = 300, learning_rate = 0.01)
    # 算法在训练数据集上的拟合
    AdaBoost2.fit(X_train[predictors],y_train)
    # 算法在测试数据集上的预测
    pred2 = AdaBoost2.predict(X_test[predictors])
    
    # 返回模型的预测效果
    print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred2))
    print('模型的评估报告:\n',metrics.classification_report(y_test, pred2))
    

    准确率只提升了0.35%,可以考虑其他模型

    # 计算正例的预测概率,用于生成ROC曲线的数据
    y_score = AdaBoost2.predict_proba(X_test[predictors])[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
    # 计算AUC的值
    roc_auc = metrics.auc(fpr,tpr)
    
    # 绘制面积图
    plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
    # 添加边际线
    plt.plot(fpr, tpr, color='black', lw = 1)
    # 添加对角线
    plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
    # 添加文本信息
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
    # 添加x轴与y轴标签
    plt.xlabel('1-Specificity')
    plt.ylabel('Sensitivity')
    # 显示图形
    plt.show()
    

    构建GBDT模型

    # 运用网格搜索法选择梯度提升树的合理参数组合
    learning_rate = [0.01,0.05,0.1,0.2]
    n_estimators = [100,300,500]
    max_depth = [3,4,5,6]
    params = {'learning_rate':learning_rate,'n_estimators':n_estimators,'max_depth':max_depth}
    gbdt_grid = GridSearchCV(estimator = ensemble.GradientBoostingClassifier(),
                             param_grid= params, scoring = 'roc_auc', cv = 5, n_jobs = 4, verbose = 1)
    gbdt_grid.fit(X_train[predictors],y_train)
    # 返回参数的最佳组合和对应AUC值
    gbdt_grid.best_params_, gbdt_grid.best_score_
    
    # 基于最佳参数组合的GBDT模型,对测试数据集进行预测
    pred = gbdt_grid.predict(X_test[predictors])
    # 返回模型的预测效果
    print('模型的准确率为:\n',metrics.accuracy_score(y_test, pred))
    print('模型的评估报告:\n',metrics.classification_report(y_test, pred))
    

    与AdaBoost结果一致,说明GBDT采用一阶导函数的值近似残差是合理的

    # 计算违约客户的概率值,用于生成ROC曲线的数据
    y_score = gbdt_grid.predict_proba(X_test[predictors])[:,1]
    fpr,tpr,threshold = metrics.roc_curve(y_test, y_score)
    # 计算AUC的值
    roc_auc = metrics.auc(fpr,tpr)
    
    # 绘制面积图
    plt.stackplot(fpr, tpr, color='steelblue', alpha = 0.5, edgecolor = 'black')
    # 添加边际线
    plt.plot(fpr, tpr, color='black', lw = 1)
    # 添加对角线
    plt.plot([0,1],[0,1], color = 'red', linestyle = '--')
    # 添加文本信息
    plt.text(0.5,0.3,'ROC curve (area = %0.2f)' % roc_auc)
    # 添加x轴与y轴标签
    plt.xlabel('1-Specificity')
    plt.ylabel('Sensitivity')
    # 显示图形
    plt.show()
    

    相关文章

      网友评论

        本文标题:用AdaBoost和GBDT模型处理信用卡违约问题

        本文链接:https://www.haomeiwen.com/subject/somnyqtx.html