经典机器学习算法-第八章GBDT

经典机器学习算法-第八章GBDT,第1张

EDUCATION AND TRAINING

一、算法原理

  GBDT(Gradient Boosting Decision Tree)在数据分析和预测中的效果很好。它是一种基于决策树的集成算法。其中Gradient Boosting 是集成方法boosting中的一种算法,通过梯度下降来对新的学习器进行迭代。而GBDT中采用的就是CART决策树。

1.1 Boosting

  Boosting指把多个弱学习器相加,产生一个新的强学习器。经典的例子有:adaboost, GBDT, xgboost等。如果每一个弱学习器用 fi(x) 来表示的话,那么Boosting的强学习器就可以表示为:


经典机器学习算法-第八章GBDT,图片,第2张

 通俗的来说就相当于把多个学习器串联(bagging是并联)。接下来,我们就介绍一下Gradient Boosting是如何产生强学习器的。

1.2 Gradient Boosting

首先,举个例子。例如我们给定的特征x和对应的结果y是:


经典机器学习算法-第八章GBDT,图片,第3张

 我们假设给定的第一个弱学习器为 f1(x)=x ,显然,这个学习器很弱。产生的结果 f1(x)=(1,2,3) 。那我们如何来改进这个学习器呢?Boosting的思想就是,我们可以给这个弱学习器再加另一个学习器,来提高效果。经过观察我们发现,如果给第一个学习器加上一个常数10,那这个学习器就完美了。于是我们就有了


经典机器学习算法-第八章GBDT,图片,第4张

 这就完美地拟合了数据。而这个常数10就是对应的y−x ,即对应的残差。于是,一个很朴素的思想就出来了,即每次新的学习器的学习目标就是由残差产生。所以,我们假设已有n-1个弱学习器 fi(x) 组合而成的强学习器:


经典机器学习算法-第八章GBDT,图片,第5张

 下一个弱学习器 fn(x) 就把


经典机器学习算法-第八章GBDT,图片,第6张
 看做新的y,即学习的目标,进行学习。之后,我们就可以得到一个新的更强的学习器:
经典机器学习算法-第八章GBDT,图片,第7张

而其实残差呢,本质上就是二次损失函数


经典机器学习算法-第八章GBDT,图片,第8张

的导数的负数,即:


经典机器学习算法-第八章GBDT,图片,第9张

 也就是对应二次损失函数的负梯度,这也就是Gradient boosting的梯度下降的思想。并且,我们也可以将这里的二次损失函数替换成其他的损失函数,来减少异常点对于模型的影响。例如可以使用如下的Huber损失函数:


经典机器学习算法-第八章GBDT,图片,第10张

1.3 GBDT

 而GBDT则是把CART决策树作为每次弱分类器学习的方法,GBDT具体的算法如下(截图来自《The Elements of Statistical Learning》):


经典机器学习算法-第八章GBDT,图片,第11张


二、Numpy手写代码import numpy as npfrom cart import TreeNode, BinaryDecisionTree, ClassificationTree, RegressionTreefrom sklearn.model_selection import train_test_splitfrom sklearn.metrics import mean_squared_errorfrom utils import feature_split, calculate_gini, data_shuffle
### GBDT定义class GBDT(object): def __init__(self, n_estimators, learning_rate, min_samples_split, min_gini_impurity, max_depth, regression): ### 常用超参数 # 树的棵树 self.n_estimators = n_estimators # 学习率 self.learning_rate = learning_rate # 结点最小分裂样本数 self.min_samples_split = min_samples_split # 结点最小基尼不纯度 self.min_gini_impurity = min_gini_impurity # 最大深度 self.max_depth = max_depth # 默认为回归树 self.regression = regression # 损失为平方损失 self.loss = SquareLoss() # 如果是分类树,需要定义分类树损失函数 # 这里省略,如需使用,需自定义分类损失函数 if not self.regression: self.loss = None # 多棵树叠加 self.estimators = [] for i in range(self.n_estimators): self.estimators.append(RegressionTree(min_samples_split=self.min_samples_split, min_gini_impurity=self.min_gini_impurity, max_depth=self.max_depth)) # 拟合方法 def fit(self, X, y): # 前向分步模型初始化,第一棵树 self.estimators[0].fit(X, y) # 第一棵树的预测结果 y_pred = self.estimators[0].predict(X) # 前向分步迭代训练 for i in range(1, self.n_estimators): gradient = self.loss.gradient(y, y_pred) self.estimators[i].fit(X, gradient) y_pred -= np.multiply(self.learning_rate, self.estimators[i].predict(X)) # 预测方法 def predict(self, X): # 回归树预测 y_pred = self.estimators[0].predict(X) for i in range(1, self.n_estimators): y_pred -= np.multiply(self.learning_rate, self.estimators[i].predict(X)) # 分类树预测 if not self.regression: # 将预测值转化为概率 y_pred = np.exp(y_pred) / np.expand_dims(np.sum(np.exp(y_pred), axis=1), axis=1) # 转化为预测标签 y_pred = np.argmax(y_pred, axis=1) return y_pred
### GBDT分类树class GBDTClassifier(GBDT): def __init__(self, n_estimators=200, learning_rate=.5, min_samples_split=2, min_info_gain=1e-6, max_depth=2): super(GBDTClassifier, self).__init__(n_estimators=n_estimators, learning_rate=learning_rate, min_samples_split=min_samples_split, min_gini_impurity=min_info_gain, max_depth=max_depth, regression=False) # 拟合方法 def fit(self, X, y): super(GBDTClassifier, self).fit(X, y) ### GBDT回归树class GBDTRegressor(GBDT): def __init__(self, n_estimators=300, learning_rate=0.1, min_samples_split=2, min_var_reduction=1e-6, max_depth=3): super(GBDTRegressor, self).__init__(n_estimators=n_estimators, learning_rate=learning_rate, min_samples_split=min_samples_split, min_gini_impurity=min_var_reduction, max_depth=max_depth, regression=True)
### 定义回归树的平方损失class SquareLoss(): # 定义平方损失 def loss(self, y, y_pred): return 0.5 * np.power((y - y_pred), 2) # 定义平方损失的梯度 def gradient(self, y, y_pred): return -(y - y_pred)
### GBDT分类树# 导入sklearn数据集模块from sklearn import datasets# 导入波士顿房价数据集boston = datasets.load_boston()# 打乱数据集X, y = shuffle_data(boston.data, boston.target, seed=13)X = X.astype(np.float32)offset = int(X.shape[0] * 0.9)# 划分数据集X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)# 创建GBRT实例model = GBDTRegressor()# 模型训练model.fit(X_train, y_train)# 模型预测y_pred = model.predict(X_test)# 计算模型预测的均方误差mse = mean_squared_error(y_test, y_pred)print ('Mean Squared Error of NumPy GBRT:', mse)

经典机器学习算法-第八章GBDT,图片,第12张



三、scikit-learn集成方法分类器:
sklearn.ensemble.GradientBoostingClassifier(loss=’deviance’, learning_rate=0.1, n_estimators=100, subsample=1.0, criterion=’friedman_mse’, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_decrease=0.0, min_impurity_split=None, init=None, random_state=None, max_features=None, verbose=0, max_leaf_nodes=None, warm_start=False, presort=’auto’)
# GBDT# Gradient Tree Boosting 或梯度提升回归树(GBRT)是对于任意的可微损失函数的提升算法的泛化。 GBRT 是一个准确高效的现有程序, 它既能用于分类问题也可以用于回归问题。梯度树提升模型被应用到各种领域,包括网页搜索排名和生态领域。from sklearn.datasets import make_hastie_10_2from sklearn.ensemble import GradientBoostingClassifier
X, y = make_hastie_10_2(random_state=0)X_train, X_test = X[:2000], X[2000:]y_train, y_test = y[:2000], y[2000:]
clf = GradientBoostingClassifier(n_estimators=100, learning_rate=1.0, max_depth=1, random_state=0).fit(X_train, y_train)clf.score(X_test, y_test)

回归器:

sklearn.ensemble.GradientBoostingRegressor( loss=’ls’, learning_rate=0.1, n_estimators=100, subsample=1.0, criterion=’friedman_mse’, min_samples_split=2, min_samples_leaf=1, min_weight_fraction_leaf=0.0, max_depth=3, min_impurity_decrease=0.0, min_impurity_split=None, init=None, random_state=None, max_features=None, alpha=0.9, verbose=0, max_leaf_nodes=None, warm_start=False, presort=’auto’)
# GBDT# Gradient Tree Boosting 或梯度提升回归树(GBRT)是对于任意的可微损失函数的提升算法的泛化。 # GBRT 是一个准确高效的现有程序, 它既能用于分类问题也可以用于回归问题。梯度树提升模型被应用到各种领域,包括网页搜索排名和生态领域。from sklearn.datasets import make_regressionfrom sklearn.ensemble import GradientBoostingRegressorfrom sklearn.model_selection import train_test_splitX, y = make_regression(random_state=0)X_train, X_test, y_train, y_test = train_test_split( X, y, random_state=0)reg = GradientBoostingRegressor(random_state=0)reg.fit(X_train, y_train)
reg.predict(X_test[1:2])
reg.score(X_test, y_test)

  GradientBoostingClassifier和GradientBoostingRegressor的参数绝大部分相同,下面会一起进行分析,不同点会单独指出:

n_estimators: 默认是100,弱学习器的个数,或者弱学习器的最大迭代次数。一般来说 n_estimators 太小,容易欠拟合;n_estimators 太大,容易过拟合。一般选择一个适中的数值,在实际调参的过程中,常常将 n_estimators 和下面介绍的参数“学习率”(或称为“步长”) learning_rate 一起考虑。

learning_rate:默认为 0.1, 即每个弱学习器的权重缩减系数a,也称作步长。是为了防止过拟合而加上的正则化项系数,强学习器的迭代公式为fk(x)=fk-1(x)+ahk(x)。a的取值范围为(0,1}。对于同样的训练集拟合效果,较小的经典机器学习算法-第八章GBDT,图片,第13张意味着需要更多弱学习器迭代次数。通常用步长和迭代次数一起来决定算法的拟合效果,所以这两个参数 n_estimators 和 learning_rate 要一起调参,一般来说,可以从一个小一点的a开始调参。

subsample:默认为1,正则化中的子采样,防止过拟合,取值为(0,1]。注意:这里的子采样和随机森林的不一样,随机森林使用的是放回抽样,而这里是不放回抽样。如果取值为1,则使用全部样本,等于没有使用子采样。如果取值小于1,则只使用一部分样本。选择小于1的比例可以防止过拟合,但是太小又容易欠拟合。推荐在 [0.5, 0.8] 之间,默认是 1.0,即不使用子采样。

init: 即我们的初始化的时候的弱学习器f0(x),如果不输入,则用训练集样本来做样本集的初始化分类回归预测,否则用 init 参数提供的学习器做初始化分类回归预测,一般用在对数据有先验知识,或者之前做过一些拟合的时候。

loss: GBT 算法中使用的损失函数,分类模型和回归模型的损失函数是不一样的。

对于分类模型,有对数似然损失函数'deviance'和指数损失函数'exponential'两者输入选择。默认是对数似然损失函数'deviance'。一般来说,推荐使用默认的'deviance',它对二元分离和多元分类各自都有比较好的优化,而指数损失函数常用于 Adaboost 算法。

对于回归模型,有均方差'ls', 绝对损失'lad', Huber损失'huber'和分位数损失“quantile”,默认是均方差'ls'。一般来说,如果数据的噪音点不多,用默认的均方差'ls'比较好。如果是噪音点较多,推荐用抗噪音的损失函数'huber'。而如果我们需要对训练集进行分段预测的时候,则采用“quantile”。

alpha:这个参数只有 GradientBoostingRegressor 有,当使用 Huber 损失'huber'和分位数损失“quantile”时,需要指定分位数的值,默认是0.9。如果噪音点较多,可以适当降低这个分位数的值。


本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
白度搜_经验知识百科全书 » 经典机器学习算法-第八章GBDT

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情