SVM等机器学习

机器学习(九):Xgboost原理与案例分析

2019-12-24  本文已影响0人  风之舟

一、简介

Xgboost(extreme Gradient Boosting,极端梯度提升)经常被用在一些比赛中,效果显著。它是大规模并行的boosted tree的工具,是目前最快最好的开源boosted tree工具包。XGBoost所应用的算法就是GBDT(gradient boosting decision tree)的改进,使之更强大,适用于更大的范围,既可以用于分类也可以用于回归问题。Boosting算法的思想是将许多弱分类器集成在一起,形成一个强分类器。因为Xgboost是一种提升树,所以它是将许多树模型集成在一起,形成一个很强的分类器。Xgboost一般和sklearn一起使用,但是由于sklearn中没有集成Xgboost,所以需要单独下载安装。

二、原理

1、Xgboost预测

Xgboost算法是和决策树算法联系到一起的,所以我们对不同叶子结点分配不同的权重项。此时我们的预测值,\widehat{y}_{i}=\sum_{j}w_{j}x_{ij},其中w_{j}是权重项,x_{ij}是叶子结点我们的目标函数,l(y_{i},\widehat{y}_{i})=(y_{i}-\widehat{y}_{i})^2最优函数解,F^*{(\vec{x})}=arg min E_{(x,y)}[L(y,F((\vec x))],对损失函数在整个样本上计算平均值集成算法的表示,\widehat{y}_{i}=\sum_{k=1}^{K}f_{k}(x_{i}),f_{k} \in \tau我们展开来表示一下,

一开始树是0,然后往里面加数,相当于多了一个函数,再加第二棵树,相当于又多了一个函数...,这里需要保证加入新的函数能够提升整体的表达效果。提升表达效果的意思就是加上新的树之后,目标函数(就是损失)的值会下降。

2、树的复杂度

接下来定义树的复杂度,对于f_{t}的定义做一下细化,把树拆分成结构函数q(输入x输出叶子结点索引)和叶子权重部分w(输入叶子结点索引输出叶子结点分数),结构函数q把输入映射到叶子的索引号上面去,而w给定了每个索引号对应的叶子分数是什么。


如果叶子结点的个数太多,那么过拟合的风险会越大,所以要限制叶子结点的个数,所以在原来目标函数里加上一个正则化惩罚项,我们来看一下如何计算, 此时的目标函数就变成了,

3、泰勒展开求解目标函数

为了求解这个方程式,我们采用泰勒展开近似来定义一个近似的目标函数,

我们发现真实值与上一轮的预测值之间的差值是一个常数项,这个常数项可以移除,就变成了 我们将q与j合并继续进行计算, 其中被定义为每个叶子上面样本集合(每个叶子结点里面样本集合);等价于求出的值(每一个样本所在叶子索引的分数);为叶子结点数量。定义(每个叶子结点里面一阶梯度的和)(每个叶子结点里面二阶梯度的和), 目标函数相应改变为, 求偏导, 我们将求出的带回到目标函数得到, Obj代表了当我们指定一个树的结构的时候,我们在目标上面最多减少多少,可叫做结构分数,可以认为这个就是类似基尼系数一样更加一般的对于树结构进行打分的函数。Obj计算示例,

4、定义树的结构

基于目标函数Obj,对结点进行分割,分别对左右子树求目标值,然后再对未分割之前的树结构进行求目标值,最后在所有特征离选择分割后,取Gain最高的那个特征。

三、案例分析

使用到的数据集最初来自国家糖尿病/消化/肾脏疾病研究所。数据集的目标是基于数据集中包含的某些诊断测量来诊断性的预测患者是否患有糖尿病。这里的所有患者都是Pima印第安至少21岁的女性,数据集由多个医学预测变量和一个目标变量组成Outcome。预测变量包括患者的怀孕次数、BMI、胰岛素水平、年龄等。
我们先来看一下sklearn包中关于Xgboost的API:
xgboost.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100, verbosity=1, silent=None, objective="binary:logistic", booster='gbtree', n_jobs=1, nthread=None, gamma=0, min_child_weight=1, max_delta_step=0, subsample=1, colsample_bytree=1, colsample_bylevel=1, colsample_bynode=1, reg_alpha=0, reg_lambda=1, scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, missing=None, **kwargs)

booster
    gbtree 树模型做为基分类器(默认)
    gbliner 线性模型做为基分类器
silent
    silent=0时,输出中间过程(默认)
    silent=1时,不输出中间过程
nthread
    nthread=-1时,使用全部CPU进行并行运算(默认)
    nthread=1时,使用1个CPU进行运算。
scale_pos_weight
    正样本的权重,在二分类任务中,当正负样本比例失衡时,设置正样本的权重,模型效果更好。例如,当正负样本比例为1:10时,scale_pos_weight=10。
n_estimatores
    含义:总共迭代的次数,即决策树的个数
    调参:
early_stopping_rounds
    含义:在验证集上,当连续n次迭代,分数没有提高后,提前终止训练。
    调参:防止overfitting。
max_depth
    含义:树的深度,默认值为6,典型值3-10。
    调参:值越大,越容易过拟合;值越小,越容易欠拟合。
min_child_weight
    含义:默认值为1,。
    调参:值越大,越容易欠拟合;值越小,越容易过拟合(值较大时,避免模型学习到局部的特殊样本)。
subsample
    含义:训练每棵树时,使用的数据占全部训练集的比例。默认值为1,典型值为0.5-1。
    调参:防止overfitting。
colsample_bytree
    含义:训练每棵树时,使用的特征占全部特征的比例。默认值为1,典型值为0.5-1。
    调参:防止overfitting。
learning_rate
    含义:学习率,控制每次迭代更新权重时的步长,默认0.3。
    调参:值越小,训练越慢。
    典型值为0.01-0.2。
objective 目标函数
    回归任务
        reg:linear (默认)
        reg:logistic 
    二分类
        binary:logistic     概率 
        binary:logitraw   类别
    多分类
        multi:softmax  num_class=n   返回类别
        multi:softprob   num_class=n  返回概率
    rank:pairwise 
eval_metric
    回归任务(默认rmse)
        rmse--均方根误差
        mae--平均绝对误差
    分类任务(默认error)
        auc--roc曲线下面积
        error--错误率(二分类)
        merror--错误率(多分类)
        logloss--负对数似然函数(二分类)
        mlogloss--负对数似然函数(多分类)

gamma
    惩罚项系数,指定节点分裂所需的最小损失函数下降值。
    调参:
alpha
    L1正则化系数,默认为1
lambda
    L2正则化系数,默认为1

接下来我们开始使用里面的参数进行分类,首先先把需要的包写出来,

from xgboost import XGBClassifier
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score
from xgboost import plot_importance
import matplotlib.pyplot as plt
from sklearn.model_selection import GridSearchCV,StratifiedKFold

1、首先看一下数据集,并进行简单的处理

def dataset():
    """
    获取数据集并进行处理
    :return:
    """
    # 获取数据集
    data = pd.read_csv('../../数据集/机器学习/集成学习/糖尿病患者/PimaIndiansdiabetes.csv')
    print(data)
    # 将特征值与目标值分开
    y = data.iloc[:, 8]
    x = data.drop(columns='Outcome', axis=1)
    # 分割成训练集与测试集
    seed = 7
    x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.33, random_state=seed)
    return x,y,x_train, x_test, y_train, y_test
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()

2、使用Xgboost进行分类预测

def xgboost(x_train, x_test, y_train, y_test):
    """
    利用xgboost对癌症数据进行分类
    :return:
    """
    #xgboost进行训练
    xgb = XGBClassifier()
    xgb.fit(x_train,y_train)
    y_predict = xgb.predict(x_test)
    accuracy = accuracy_score(y_test, y_predict)
    print("准确率:%.2f%%" % (accuracy*100))
    return None
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    xgboost(x_train, x_test, y_train, y_test)

3、将Xgboost损失函数的变化过程输出

def xgboot_steps(x_train, x_test, y_train, y_test):
    """
    将xgboost选择树的过程分步展示
    :return:
    """
    xgb = XGBClassifier()
    eval_set = [(x_test,y_test)]
    xgb.fit(x_train, y_train,early_stopping_rounds=10,eval_metric="logloss",eval_set=eval_set,verbose=True)
    y_predict = xgb.predict(x_test)
    accuracy = accuracy_score(y_test, y_predict)
    print("准确率:%.2f%%" % (accuracy*100))
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    xgboot_steps(x_train, x_test, y_train, y_test)
通过上图我们发现,随着树的增加,损失函数在下降,在32时达到最低,之后开始上升,说明在32的时候效果最好。

4、画图观察8个特征的权重

def show_importance(x,y):
    """
    画图展示出特征的重要程度
    :return:
    """
    xgb = XGBClassifier()
    xgb.fit(x,y)
    plot_importance(xgb)
    plt.show()
    return None
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    show_importance(x,y)

5、使用网格搜索进行调优

def gridsearchCV(x_train, y_train):
    """
    使用网格搜索进行超参数调优
    :return:
    """
    #1、learning rate 学习率
    #2、tree(max_depth、min_child_weight、subsample、colsample_bytree、gamma
    #3、gamma
    #4、正则化参数(lambda、alpha)
    learning_rate = [0.0001,0.001,0.01,0.1,0.2,0.3]
    param_rate = dict(learning_rate=learning_rate)  #必须是字典格式

    #StratifiedKFold是一种将数据集中每一类样本数据按均等方式拆分的方法。
    kfold = StratifiedKFold(n_splits=10,shuffle=True,random_state=7)

    xgb = XGBClassifier()
    grid_search = GridSearchCV(xgb,param_grid=param_rate,scoring="neg_log_loss",n_jobs=-1,cv=kfold)
    grid_result = grid_search.fit(x_train,y_train)

    print("Best:%f using %s" % (grid_result.best_score_,grid_result.best_params_))

    means =grid_result.cv_results_['mean_test_score']
    params = grid_result.cv_results_['params']
    for mean,param in zip(means,params):
        print("%f with: %r" % (mean,param))
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    gridsearchCV(x_train, y_train)

四、补充:Adaboost算法

1、简介

AdaBoost,是英文"Adaptive Boosting"(自适应增强)的缩写,它的自适应在于:前一个基本分类器分错的样本会得到加强,加权后的全体样本再次被用来训练下一个基本分类器。同时,在每一轮中加入一个新的弱分类器,直到达到某个预定的足够小的错误率或达到预先指定的最大迭代次数。

2、算法流程

给定一个训练数据集T={\lbrace (x_{1},y_{1}),({x_{1},y_{2}),...(x_{N},y_{N})} \rbrace}其中实例x \in \chi,而实例空间\chi \subset \mathbb{R}^{n}y_{i}属于标记集合{-1,1},Adaboost的目的就是从训练数据中学习一系列弱分类器或基本分类器,然后将这些弱分类器组合成一个强分类器。

3、案例

我们还是使用上面的数据集,用AdaBoost算法跑一遍看一下准确率,

def gridsearchCV(x_train, y_train):
    """
    使用网格搜索进行超参数调优
    :return:
    """
    #1、learning rate 学习率
    #2、tree(max_depth、min_child_weight、subsample、colsample_bytree、gamma
    #3、gamma
    #4、正则化参数(lambda、alpha)
    learning_rate = [0.0001,0.001,0.01,0.1,0.2,0.3]
    param_rate = dict(learning_rate=learning_rate)  #必须是字典格式

    #StratifiedKFold是一种将数据集中每一类样本数据按均等方式拆分的方法。
    kfold = StratifiedKFold(n_splits=10,shuffle=True,random_state=7)

    xgb = XGBClassifier()
    grid_search = GridSearchCV(xgb,param_grid=param_rate,scoring="neg_log_loss",n_jobs=-1,cv=kfold)
    grid_result = grid_search.fit(x_train,y_train)
    print("Best:%f using %s" % (grid_result.best_score_, grid_result.best_params_))

    ada = AdaBoostClassifier()
    grid_search_ada = GridSearchCV(ada, param_grid=param_rate, scoring="neg_log_loss", n_jobs=-1, cv=kfold)
    grid_result_ada = grid_search_ada.fit(x_train, y_train)
    print("Best:%f using %s" % (grid_result_ada.best_score_, grid_result_ada.best_params_))
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    gridsearchCV(x_train, y_train)

这是Xgboost和Adaboost算法learning_rate参数的最优值,然后我们分别看一下在最优参数下两个算法的准确率,

def adaboost(x_train, x_test, y_train, y_test):
    """
    使用adaboost算法进行分类预测
    :return:
    """
    ada = AdaBoostClassifier(learning_rate=0.01)
    ada.fit(x_train,y_train)
    y_predict = ada.predict(x_test)
    accuracy = accuracy_score(y_test, y_predict)
    print("准确率:%.2f%%" % (accuracy * 100))
    return None
if __name__ == "__main__":
    x,y,x_train, x_test, y_train, y_test = dataset()
    xgboost(x_train, x_test, y_train, y_test)
    adaboost(x_train, x_test, y_train, y_test)
上面是xgboost的准确率,下面是adaboost的准确率,虽然在这里可以看到adaboost的准确率稍微低一点,但是因为数据集和参数的原因(多个参数调优)结果不一定。有兴趣的同学可以去试一下!
Xgboost算法的学习到这里就结束了,有不明白的同学可以在下方留言。
上一篇下一篇

猜你喜欢

热点阅读