GBDT(Gradient Boosting Decision Tree 梯度提升决策树)算法近年十分流行,被广泛应用于各类数据挖掘以及机器学习的比赛之中并有着良好的表现。下面让我们来走进这个算法。
起源
提起GBDT的起源,我们不得不引出以下几个概念。
集成学习
引用百科中的一段话:
集成学习是使用一系列学习器进行学习,并使用某种规则把各个学习结果进行整合从而获得比单个学习器更好的学习效果的一种机器学习方法。一般情况下,集成学习中的多个学习器都是同质的"弱学习器"。
所谓“同质”,是指集成中只包含同种类型的个体学习器。所谓“弱学习器”,是指泛化性能略优于随机猜测的学习器,例如在二分类问题上精度略高于50%的分类器。换句话说,弱学习器的结果接近于靠猜。
集成学习通过将多个学习器进行结合,通常可以获得比单一学习器显著优越的泛化性能,这对弱学习器尤明显。如何结合个体学习器,就是集成学习研究的核心。目前的集成学习方法大致可分为两大类:1)个体学习器间存在强依赖关系、必须串行生成的序列化方法,代表是Boosting;2)个体学习器间不存在强依赖关系、可同时生成的并行化方法,代表是Bagging和随机森林(Random Forest)。
Boosting
Boosting是一族可将弱学习器提升为强学习器的算法。
Boosting算法原理:
- 先对N个训练样本S1的学习得到一个基分类器M1;
- 将S1中分错的样本和其他新的数据一起构成新的N个训练样本S2,再得到一个基分类器M2;
- 将S1和S2中都分错的样本和其他新的数据一起构成新的N个训练样本S3,再得到一个基分类器M3;
- 以此类推,直至基学习器数达到事先指定的值T,最终将所有基学习器进行加权结合。
简单来说,就是基于同一训练集和同一个算法训练出T个基学习器,每一轮训练都针对上一轮的训练结果调整样本分布。
Boosting族算法最著名的代表是AdaBoost。
Bagging
Bagging是Bootstrap AGGregatING的缩写,基于自助采样法(bootstrap sampling)(一种有放回的抽样方法,即可能抽到重复的样本)。
Bagging算法原理:
- 使用自助采样法采样出T个含有m个训练样本的采样集,然后基于每个采样集训练出一个基学习器,再将这些基本学习器进行结合。
- 在对预测输出进行结合时,Bagging通常对分了任务使用简单投票法,对回归任务使用简单平均法。
Gradient Boosting
Gradient Boosting是一种Boosting的方法,它主要的思想是,每一次建立模型是在之前建立模型损失函数的梯度下降方向。损失函数是评价模型性能(一般为拟合程度+正则项),认为损失函数越小,性能越好。而让损失函数持续下降,就能使得模型不断改性提升性能,其最好的方法就是使损失函数沿着梯度方向下降。Gradient Boost是一个框架,里面可以套入很多不同的算法。
GBDT应用
分类
from sklearn import ensemble
clf = ensemble.GradientBoostingClassifier()
gbdt_model = clf.fit(X_train, y_train) # Training model
predicty_x = gbdt_model.predict_proba(test_x)[:, 1] # predict: probablity of 1
# 包含的参数
# loss = loss, learning_rate = learning_rate, n_estimators = n_estimators,
# min_samples_split = min_samples_split,
# min_samples_leaf = min_samples_leaf,
# min_weight_fraction_leaf = min_weight_fraction_leaf,
# max_depth = max_depth, init = init, subsample = subsample,
# max_features = max_features,
# random_state = random_state, verbose = verbose,
# max_leaf_nodes = max_leaf_nodes, warm_start = warm_start,
# presort = presort
回归
from sklearn import ensemble
clf = ensemble.GradientBoostingRegressor()
gbdt_model = clf.fit(X_train, y_train) # Training model
y_upper = gbdt_model.predict(x_test) # predict
构建新特征
思想:GBDT每棵树的路径直接作为LR输入特征使用。
用已有特征训练GBDT模型,然后利用GBDT模型学习到的树来构造新特征,最后把这些新特征加入原有特征一起训练模型。构造的新特征向量是取值0/1的,向量的每个元素对应于GBDT模型中树的叶子结点。当一个样本点通过某棵树最终落在这棵树的一个叶子结点上,那么在新特征向量中这个叶子结点对应的元素值为1,而这棵树的其他叶子结点对应的元素值为0。新特征向量的长度等于GBDT模型里所有树包含的叶子结点数之和。
# 弱分类器的数目
n_estimator = 10
# 随机生成分类数据。
X, y = make_classification(n_samples=80000)
# 切分为测试集和训练集,比例0.5
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.5)
# 将训练集切分为两部分,一部分用于训练GBDT模型,另一部分输入到训练好的GBDT模型生成GBDT特征,然后作为LR的特征。这样分成两部分是为了防止过拟合。
X_train, X_train_lr, y_train, y_train_lr = train_test_split(X_train, y_train, test_size=0.5)
# 调用GBDT分类模型。
grd = GradientBoostingClassifier(n_estimators=n_estimator)
# 调用one-hot编码。
grd_enc = OneHotEncoder()
# 调用LR分类模型。
grd_lm = LogisticRegression()
# 使用X_train训练GBDT模型,后面用此模型构造特征
grd.fit(X_train, y_train)
# fit one-hot编码器
grd_enc.fit(grd.apply(X_train)[:, :, 0])
# 使用训练好的GBDT模型构建特征,然后将特征经过one-hot编码作为新的特征输入到LR模型训练。
grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)
# 用训练好的LR模型多X_test做预测
y_pred_grd_lm = grd_lm.predict_proba(grd_enc.transform(grd.apply(X_test)[:, :, 0]))[:, 1]
# 根据预测结果输出
fpr_grd_lm, tpr_grd_lm, _ = roc_curve(y_test, y_pred_grd_lm)