<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          100天搞定機(jī)器學(xué)習(xí)|Day61 手算+可視化,終于徹底理解了 XGBoost

          共 8999字,需瀏覽 18分鐘

           ·

          2021-02-26 10:49

          ↑↑↑點(diǎn)擊上方藍(lán)字,回復(fù)資料,10個(gè)G的驚喜

          我們已經(jīng)學(xué)習(xí)了XGBoost淵源及優(yōu)點(diǎn)、模型原理及優(yōu)化推導(dǎo)、模型參數(shù)解析:100天搞定機(jī)器學(xué)習(xí)|Day60 遇事不決,XGBoost,文章有點(diǎn)太枯燥,大家可能對其中的公式推導(dǎo)和參數(shù)還不甚理解。

          今天我們以西瓜數(shù)據(jù)集為例,配合手算,拆開揉碎,深入理解公式與代碼之間的內(nèi)在聯(lián)系,然后用可視化的方式更形象地看透 XGBoost 的原理

          本文又硬又干,歡迎同學(xué)們來個(gè)素質(zhì)三連:在看、收藏、轉(zhuǎn)發(fā),沒有關(guān)注的同學(xué)也來個(gè)關(guān)注下哈↓↓↓↓↓↓

          #本文用到的庫
          import numpy as np
          import pandas as pd
          from sklearn.model_selection import train_test_split
          from sklearn import preprocessing
          from xgboost.sklearn import XGBClassifier
          from xgboost import plot_tree
          import matplotlib.pyplot as plt
          from xgboost import plot_importance
          from sklearn.model_selection import GridSearchCV
          from sklearn.metrics import classification_report, precision_recall_curve

          西瓜數(shù)據(jù)集及預(yù)處理

          def getDataSet():
              dataSet = [
                  ['青綠''蜷縮''濁響''清晰''凹陷''硬滑', 0.697, 0.460, 1],
                  ['烏黑''蜷縮''沉悶''清晰''凹陷''硬滑', 0.774, 0.376, 1],
                  ['烏黑''蜷縮''濁響''清晰''凹陷''硬滑', 0.634, 0.264, 1],
                  ['青綠''蜷縮''沉悶''清晰''凹陷''硬滑', 0.608, 0.318, 1],
                  ['淺白''蜷縮''濁響''清晰''凹陷''硬滑', 0.556, 0.215, 1],
                  ['青綠''稍蜷''濁響''清晰''稍凹''軟粘', 0.403, 0.237, 1],
                  ['烏黑''稍蜷''濁響''稍糊''稍凹''軟粘', 0.481, 0.149, 1],
                  ['烏黑''稍蜷''濁響''清晰''稍凹''硬滑', 0.437, 0.211, 1],
                  ['烏黑''稍蜷''沉悶''稍糊''稍凹''硬滑', 0.666, 0.091, 0],
                  ['青綠''硬挺''清脆''清晰''平坦''軟粘', 0.243, 0.267, 0],
                  ['淺白''硬挺''清脆''模糊''平坦''硬滑', 0.245, 0.057, 0],
                  ['淺白''蜷縮''濁響''模糊''平坦''軟粘', 0.343, 0.099, 0],
                  ['青綠''稍蜷''濁響''稍糊''凹陷''硬滑', 0.639, 0.161, 0],
                  ['淺白''稍蜷''沉悶''稍糊''凹陷''硬滑', 0.657, 0.198, 0],
                  ['烏黑''稍蜷''濁響''清晰''稍凹''軟粘', 0.360, 0.370, 0],
                  ['淺白''蜷縮''濁響''模糊''平坦''硬滑', 0.593, 0.042, 0],
                  ['青綠''蜷縮''沉悶''稍糊''稍凹''硬滑', 0.719, 0.103, 0]
              ]

              features = ['color''root''knocks''texture''navel''touch''density''sugar','good']
              dataSet = np.array(dataSet)
              df = pd.DataFrame(dataSet,columns=features)
              for feature in features[0:6]:
                  le = preprocessing.LabelEncoder()
                  le = le.fit(df[feature])
                  df[feature] = le.transform(df[feature])
              df.iloc[:,6:8]=df.iloc[:,6:8].astype(float)
              df['good']=df['good'].astype(int)
              return df

          本文中,我們使用sklearn風(fēng)格的接口,并使用sklearn風(fēng)格的參數(shù)。xgboost.XGBClassifier實(shí)現(xiàn)了scikit-learn 的分類模型API:

          xgboost.XGBClassifier(max_depth=3, learning_rate=0.1, n_estimators=100, 
               silent=True, 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, reg_alpha=0, reg_lambda=1,
               scale_pos_weight=1, base_score=0.5, random_state=0, seed=None, 
               missing=None, **kwargs)

          為方便手算,我們設(shè)n_estimators=2,即XGBoost僅2棵樹,正則項(xiàng),系數(shù)=1,gamma=0。

          #訓(xùn)練模型
          df = getDataSet()
          X, y = df[df.columns[:-1]],df['good']
          X_train, X_test, y_train, y_test = train_test_split(X,y, random_state=0)
          sklearn_model_new = XGBClassifier(n_estimators=2,max_depth=5,learning_rate= 0.1, verbosity=1, objective='binary:logistic',random_state=1)
          sklearn_model_new.fit(X_train, y_train)
          model.fit(X_train, y_train)

          XGBoost可視化

          現(xiàn)在看一下XGBoost的內(nèi)部結(jié)構(gòu),看看樹的形狀。XGBoost可視化可使用xgboost.plot_tree方法:

          xgboost.plot_tree(booster, fmap='', num_trees=0, rankdir='UT', ax=None, **kwargs)

          參數(shù):

          booster:一個(gè)Booster對象, 一個(gè) XGBModel 對象
          fmap:一個(gè)字符串,給出了feature map 文件的文件名
          num_trees:一個(gè)整數(shù),制定了要繪制的子數(shù)的編號。默認(rèn)為 0
          rankdir:一個(gè)字符串,它傳遞給graphviz的graph_attr
          ax:一個(gè)matplotlib Axes 對象。特征重要性將繪制在它上面。如果為None,則新建一個(gè)Axes
          kwargs:關(guān)鍵字參數(shù),用于傳遞給graphviz 的graph_attr

          XGBoost很多函數(shù)會用的一個(gè)參數(shù)fmap (也就是feature map),但是文檔里面基本沒解釋這個(gè)fmap是怎么產(chǎn)生的,Kaggle上有好心人提供了解決方案: https://www.kaggle.com/mmueller/xgb-feature-importance-python

          def ceate_feature_map(features):
              outfile = open('xgb.fmap''w')
              i = 0
              for feat in features:
                  outfile.write('{0}\t{1}\tq\n'.format(i, feat))
                  i = i + 1
              outfile.close()
          ceate_feature_map(df.columns)

          這個(gè)函數(shù)就是根據(jù)給定的特征名字(直接使用數(shù)據(jù)的列名稱), 按照特定格式生成一個(gè)xgb.fmap文件, 這個(gè)文件就是XGBoost文檔里面多次提到的fmap, 注意使用的時(shí)候, 直接提供文件名, 比如fmap='xgb.fmap'.

          有了fmap, 在調(diào)用plot_tree函數(shù)的時(shí)候, 直接指定fmap文件即可:

          plot_tree(fmap='xgb.fmap')

          調(diào)整清晰度需要使用plt.gcf()方法

          plot_tree(sklearn_model_new,fmap='xgb.fmap',num_trees=0)
          fig = plt.gcf()
          fig.set_size_inches(150, 100)
          plt.show()
          第一棵樹
          plot_tree(sklearn_model_new,fmap='xgb.fmap',num_trees=1)
          fig = plt.gcf()
          fig.set_size_inches(150, 100)
          plt.show()
          第二棵樹

          重頭戲分割線————手算

          先看看X_train第一棵樹僅以含糖率為分割點(diǎn),對其排序,分割點(diǎn)為兩點(diǎn)間的均值

          0.186為何可以成為根節(jié)點(diǎn)呢?這個(gè)咱們待會兒再算。

          那我們就算一下,不過在此之前還要再復(fù)習(xí)一下?lián)p失函數(shù) logloss:

          由于后面需要用到logloss的一階導(dǎo)數(shù)以及二階導(dǎo)數(shù),這里先簡單推導(dǎo)一下。

          其中

          在一階導(dǎo)的基礎(chǔ)上再求一次有(其實(shí)就是sigmod函數(shù)求導(dǎo))

          base_score初始值 0.5 ,我們計(jì)算每個(gè)樣本的一階導(dǎo)數(shù)值和二階導(dǎo)數(shù)值
          樣本的一階導(dǎo)數(shù)值:
          樣本的二階導(dǎo)數(shù)值:

          =2.5
          =-2.5
          =1.25
          =1.75

          計(jì)算最優(yōu)的權(quán)重:

          所以:
          =-0.111111111
          =0.090909091

          tips:上述結(jié)果直接計(jì)算與圖中不符,這里要記得乘以學(xué)習(xí)率:0.1

          第一棵樹即為:

          回答開頭的問題,第一棵樹為何以含糖率的0.1856為根節(jié)點(diǎn)?必然是所有特征中此處分割的 gain 最大!看一下這個(gè)公式

          計(jì)算結(jié)果為5.0505,其他特征的gain小于它,原理類似這里就不挨個(gè)算了。

          另一個(gè)問題,為何分裂到此怎么就停了呢?
          XGBClassifier參數(shù)min_child_weight默認(rèn)值 1 ,是葉子節(jié)點(diǎn)包含樣本的所有二階偏導(dǎo)數(shù)之和,代表子節(jié)點(diǎn)的權(quán)重閾值。它刻畫的是:對于一個(gè)葉子節(jié)點(diǎn),當(dāng)對它采取劃分之后,它的所有子節(jié)點(diǎn)的權(quán)重之和的閾值。如果它的所有子節(jié)點(diǎn)的權(quán)重之和小于該閾值,則該葉子節(jié)點(diǎn)不值得繼續(xù)分裂。

          本例中如再以0.344處或其他特征某處分裂則必有>1,所以就不分裂了。min_child_weight的值較大時(shí),可以避免模型學(xué)習(xí)到局部的特殊樣本。本例如將其值改為0.2,就會發(fā)現(xiàn)還會分裂(如下圖):

          感興趣的同學(xué)可以試試,能算出-0.04和0.12嗎?

          還以min_child_weight默認(rèn)值為 1,然后,生成第二棵樹,此處僅需按第一棵樹的預(yù)測結(jié)果更新base_score的值,注意:預(yù)測結(jié)果要經(jīng)過sigmod映射,即當(dāng)預(yù)測為0時(shí),base_score更新為
          當(dāng)預(yù)測為0時(shí),base_score更新為

          進(jìn)一步計(jì)算,,大家可以試一下,結(jié)果如圖。

          因?yàn)槲覀冎挥袃煽脴洌卣鬟x擇僅使用了含糖率,分裂了兩次,so,特征重要性為2

          plot_importance(sklearn_model_new)

          XGBoost網(wǎng)格搜索調(diào)參

          參數(shù)調(diào)整是機(jī)器學(xué)習(xí)中的一門暗藝術(shù),模型的最優(yōu)參數(shù)可以依賴于很多場景。所以要創(chuàng)建一個(gè)全面的指導(dǎo)是不可能的。XGBoost使用sklearn風(fēng)格的接口,并使用網(wǎng)格搜索類GridSeachCV來調(diào)參,非常方便。gsCv.best_params_獲取最優(yōu)參數(shù),添加新的參數(shù)進(jìn)來,然后再次GridSearchCV。

          也可以一把梭哈,把重要參數(shù)一次懟進(jìn)去。

          gsCv = GridSearchCV(sklearn_model_new,
                             {'max_depth': [4,5,6],
                              'n_estimators': [5,10,20],
                             'learning_rate ': [0.05,0.1,0.3,0.5,0.7],
                              'min_child_weight':[0.1,0.2,0.5,1]
                             })
          gsCv.fit(X_train,y_train)
          print(gsCv.best_params_)

          {'learning_rate ': 0.05, 'max_depth': 4, 'min_child_weight': 0.1, 'n_estimators': 5} 以此參數(shù)重新訓(xùn)練即可。

          也可以加一下老胡的微信
          圍觀朋友圈~~~


          推薦閱讀

          (點(diǎn)擊標(biāo)題可跳轉(zhuǎn)閱讀)

          所以,機(jī)器學(xué)習(xí)和深度學(xué)習(xí)的區(qū)別是什么?
          機(jī)器學(xué)習(xí)避坑指南:訓(xùn)練集/測試集分布一致性檢查
          機(jī)器學(xué)習(xí)深度研究:特征選擇中幾個(gè)重要的統(tǒng)計(jì)學(xué)概念

          老鐵,三連支持一下,好嗎?↓↓↓

          瀏覽 74
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  www.综合久久 | 欧洲成人免费视频 | 日韩AV手机版 | 啊啊啊啊啊www. | 操操操操操操操操操操操操操操操操操逼 |