一、Bagging与Pasting
这里的 pasting 表示每次从训练集中抽取后数据就不返回了,叫作重采样。可以直观地感受,使用 pasting 的话分类器之间的相关性将强于不使用。在未使用 pasting 的情况下,模型的泛化效果更好。
from sklearn.ensemble import BaggingClassifier
from sklearn.tree import DecisionTreeClassifier
# 构建集成学习参数列表
bag_clf = BaggingClassifier(
# 使用500个决策树构建集成学习器
DecisionTreeClassifier(), n_estimators = 500,
# 每次训练从训练集中随机抽出100个样本,如果使用pasting则bootstrap=False
# n_jobs表示使用多少个CPU核心,如果n_jobs=-1表示全部使用
max_samples = 100, bootstrap = True, n_jobs = -1)
# 训练学习器
bag_clf.fit(X_train,y_train)
# 使用测试集预测
y_pred = bag_clf.predict(X_test)
二、out-of-bag estimate
由于Bagging大都使用自助采样,如上面谈到的。因此对训练集合来说,有63.2%的样本会被选上,可以使用这些被选上的数据作为训练样本,而余下的36.8作为测试集(证明参照极限,得到自然对数的倒数)。基于测试样本,通过如下代码可以求得测试样本的准确率。
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators = 500,
# obb_score = True 表示使用包外估计
# bootstrap = True 使用自助采样
bootstrap = True, n_jobs = -1, oob_score= True)
bag_clf.fit(X_train, y_train)
bag_clf.oob_score_
在我们给的测试集上求准确率:
from sklearn.metrics import accuracy_score
# 基于测试集上的预测值
y_pred = bag_clf.predict(X_test)
# 求解预测结果
accuracy_score(y_test, y_pred)
获取决策的函数,以输出结果的形式给出:
bag_clf.oob_decision_function_
三、Random Patches
上面是对样本的随机抽取,但有时对于高维输入特征,可以采用随机采样特征的方法。比如在决策树分裂节点的时候就会根据衡量所有特征然后看哪个增益率最大(C4.5决策树策略),这样会导致时间开销大,一种做法是随机选取某些特征作为候选集合,再从候选集合中选择最优的特征,这很类似于随机森林的划分策略。
基于之前的代码,加上一行:
bag_clf = BaggingClassifier(
DecisionTreeClassifier(), n_estimators = 500,
# 是否使用包外预测
bootstrap = True, n_jobs = -1, oob_score= True,
# 对特征进行随机抽取
bootstrap_features= True, max_features = 0.2)
四、Random Forest
传统决策树是从所有属性 d 中根据某个策略(如增益率或基尼指数等)选择最优特征进行划分,而Random Forest每次是从所有属性的子属性集合 k 中选择最优特征。一般情况下,
from sklearn.ensemble import RandomForestClassifier
# 构建500个决策树,限制叶子节点最大为16,n_jobs表示使用可使用的cpu核数,-1表示全部使用
rnd_clf = RandomForestClassifier(n_estimators = 500, max_leaf_nodes = 16, n_jobs = -1)
rnd_clf.fit(X_train, y_train)
这段代码与下面这段代码功能类似:
bag_clf = BaggingClassifier(
DecisionTreeClassifier(splitter = "random", max_leaf_nodes = 16),
n_estimators = 500, max_samples = 1.0, bootstrap = True, n_jobs = -1)
五、Extremely Randomized Tree
Random Forest在从所有特征的子集合中选择最好的特征进行划分,而Extremely Randomized Tree对下一步如何分裂不采取选取最优特征的方法,而是随机选取。这样会带来很大的偏差,但因此方差会减小。
要创建Extremely Randomized Tree,在sklearn中一般使用ExtraTreesClassifier类,其用法与RandomForestClassifier相似
from sklearn.ensemble import ExtraTreesClassifier
rnd_clf = ExtraTreesClassifier(n_estimators = 500, max_leaf_nodes = 16, n_jobs = -1)
六、Feature Importance
在决策树中,比较重要的特征一般都靠近根节点,而不重要的特征一般都出现在靠近叶子节点的附近。
from sklearn.datasets import load_iris
iris = load_iris()
rnd_clf = RandomForestClassifier(n_estimators = 500, n_jobs = -1)
rnd_clf.fit(iris["data"], iris["target"])
# 获取特征的名称,获取特征重要性的值
for name, score in zip(iris["feature_names"], rnd_clf.feature_importances_):
print(name, score)
七、AdaBoost
Boosting族可以将弱学习器提升为强学习的算法。其工作机制是先从初始训练集训练出一个基学习器,再根据基学习器的表现对训练样本分布进行调整,使得先前基学习器做错的训练样本在后续会受到更多关注。
AdaBoost通过调整样本的权重来训练后续的学习器
from sklearn.ensemble import AdaBoostClassifier
ada_clf = AdaBoostClassifier(
# 使用默认的决策树,该决策树有一个节点与两个子节点
DecisionTreeClassifier(max_depth = 1), n_estimators = 200,
# 使用算法SAMME的变体SAMME.R,SAMME.R基于类别概率,往往效果更好
algorithm = "SAMME.R", learning_rate = 0.5)
ada_clf.fit(X_train, y_train)
八、Gradient Boosting
与AdaBoost通过调整样本权重训练后续的学习器不同的是,Gradient Boosting 通过拟合前一个学习器的残差来训练新的学习器
from sklearn.tree import DecisionTreeRegressor
# 第一个学习器
tree_reg1 = DecisionTreeRegressor(max_depth = 2)
tree_reg1.fit(X_train, y_train)
# 第二个学习器的训练基于前一个学习器的残差
y2 = y_train - tree_reg1.predict(X_train)
tree_reg2 = DecisionTreeRegressor(max_depth = 2)
tree_reg2.fit(X_train, y2)
y3 = y2 - tree_reg1.predict(X_train)
tree_reg3 = DecisionTreeRegressor(max_depth = 2)
tree_reg3.fit(X_train, y3)
y_pred = sum(tree.predict(X_test) for tree in (tree_reg1, tree_reg2, tree_reg3)
上面代码是整个学习过程的细化,下述代码可以简化整个过程:
from sklearn.ensemble import GradientBoostingRegressor
# max_depth表示树的最大深度。
gbrt = GradientBoostingRegressor(max_depth = 2, n_estimators = 3, learning_rate = 1.0)
gbrt.fit(X_train, y_train)
在GBRT中,决策树的数目(对于本例来说基学习器是决策树)是个超参数,为了寻找最优情况下的树的数目,可以穷举小于最大训练器数目下的所有情况。
gbrt = GradientBoostingRegressor(max_depth = 2, n_estimators = 120)
gbrt.fit(X_train, y_train)
# 依次计算直到120个学习器的误差
errors = [mean_squared_error(y_val, y_pred) for y_pred in gbrt.staged_predict(X_val)]
# 取误差最小时,学习器的数目
bst_n_estimators = np.argmin(errors)
gbrt_best = GradientBoostingRegressor(max_depth = 2, n_estimators = bst_n_estimators)
gbrt_best.fit(X_train, y_train)
也可以使用提前终止策略
# warm_start = True,使学习器可以保持当前的状态直到fit
gbrt = GradientBoostingRegressor(max_depth = 2, warm_start = True)
min_val_error = float("inf")
# 记录
error_going_up = 0
for n_estimators in range(1, 120):
gbrt.n_estimators = n_estimators
gbrt.fit(X_train, y_train)
y_pred = gbrt.predict(X_val)
val_error = mean_squared_error(y_val, y_pred)
# 如果连续五次准确率未提升,则提前终止
if val_error < min_val_error:
min_val_error = val_error
error_going_up = 0
else:
error_going_up += 1
if error_going_up == 5:
break
参考文献:
《Hands-ON Machine Learning with Scikit-Learn & TensorFlow》
周志华的《机器学习》