一. 集成学习思想
集成学习
原理
集成学习是机器学习中的一种思想,它通过多个模型的组合形成一个精度更高的模型,参与组合的模型称为弱学习器(基学习器)
。训练时,使用训练集依次训练出这些弱学习器,对未知样本进行预测时,使用这些弱学习器联合进行预测
优势
弱弱变强, 强强联合
集成学习分类
-
Bagging:随机森林
-
Boosting:Adaboost(自适应)、GBDT、XGBoost、LightGBM
Bagging思想
Bagging思想
-
Bagging: 随机森林算法: 又称装袋算法或者自举汇聚法
-
有放回的抽样(booststrap抽样)产生不同的训练集,从而训练不同的学习器
-
通过
平权投票
、多数表决的方式决定预测结果在分类问题中,会使用多数投票统计结果
在回归问题中,会使用求均值统计结果
-
弱学习器可以
并行训练
-
基本的弱学习器算法模型,如: Linear、Ridge、Lasso、Logistic、Softmax、ID3、C4.5、CART、SVM、KNN均可
Boosting思想
思想原理
每一个训练器重点关注前一个训练器不足
的地方进行训练通过加权投票
的方式,得出预测结果
串行的训练方式
举例
随着学习的积累从弱到强每新加入一个弱学习器
,整体能力就会得到提升代表算法:Adaboost,GBDT,XGBoost,LightGBM
总结
集成学习是什么
多个弱学习器组合成一个更强大的学习器,解决单一预测,进步一得到更好性能。
bagging思想
有放回的抽样
平权投票
、多数表决的方式决定预测结果
并行训练
boosting思想
重点关注前一个训练器不足
的地方进行训练
加权投票
的方式
串行的训练方式
bagging思想
二. 随机森林算法
构建方法
基本思想
随机森林是基于 Bagging 思想实现的一种集成学习算法,采用决策树模型作为每一个弱学习器(基学习器)
。训练:(1)有放回的产生训练样本
(2)随机挑选 n 个特征(n 小于总特征数量)预测:平权投票
,多数表决输出预测结果
构建步骤
概念
为什么要随机抽样训练集?如果不进行随机抽样,每棵树的训练集都一样
,那么最终训练出的树分类结果也是完全一样
。防止过拟合, 提高泛化性能
为什么要有放回地抽样?
- 如果不是有放回的抽样,那么每棵树的训练样本都是不同的,
都是没有交集的
,这样每棵树都是"有偏的"
,也就是说每棵树训练出来都是有很大的差异的
;而随机森林最后分类取决于多棵树(弱分类器)的投票表决。
- 综上:弱学习器的
训练样本既有交集也有差异数据
,更容易发挥投票表决效果
随机森林的API
API介绍
案例-泰坦尼克数据集
# 导包
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import RandomForestClassifier # 随即森丽分类
from sklearn.metrics import accuracy_score
# 定义随机森立函数
def dm01_rf_classifier():
# 数据读取
data = pd.read_csv('data/train.csv')
data.info()
# 数据基本处理
# 确定特征和标签
x = data.iloc[:, 2:-2].copy()
x.drop(['Name', 'Ticket'], inplace=True, axis='columns')
y = data.Survived
# print(x)
# print(y)
# 空值处理(填充)
x.Age = x.Age.fillna(x.Age.mean())
print(x)
# 处理字符类型 数据
x = pd.get_dummies(x)
x.drop('Sex_female', inplace=True, axis=1)
# print(x.head())
# 数据划分
x_train, x_test, y_train, y_test = train_test_split(
x, y,
test_size=0.2,
random_state=21,
stratify=y
)
# 模型训练
# 决策树模型
model1 = DecisionTreeClassifier()
model1.fit(x_train, y_train)
# 随机森林模型
model2 = RandomForestClassifier(max_depth=6)
model2.fit(x_train, y_train)
# 模型评估
print('(决策树)预测后评估:', accuracy_score(y_true=y_test, y_pred=model1.predict(x_test)))
print('(随即森林)预测后评估:', accuracy_score(y_true=y_test, y_pred=model2.predict(x_test)))
# 交叉验证网格搜索, 寻找最优超参数
estimator = RandomForestClassifier()
param = {'n_estimators': [10, 20, 30, 40, 50, 60, 70],
'max_depth': [1, 2, 3, 4, 5, 6, 7, 8, 9],
}
grid_search = GridSearchCV(estimator, param_grid=param, cv=5)
grid_search.fit(x_train, y_train)
print('(交叉验证后)预测后评估:', accuracy_score(y_true=y_test, y_pred=grid_search.predict(x_test)))
if __name__ == '__main__':
dm01_rf_classifier()
总结
boosting思想
三. Adaboost算法
基本原理
放大错误, 缩小正确
Adaptive Boosting(自适应提升)基于 Boosting思想实现的一种集成学习算法核心思想是通过逐步提高那些被前一步分类错误
的样本的权重来训练一个强分类器。
Adaboost算法推导
- 初始化训练数据权重相等,训练第 1 个学习器
如果有 100 个样本,则每个样本的初始化权重为:1/100
根据预测结果找一个错误率最小的分裂点
,计算、更新:样本权重、模型权重
- 根据新权重的样本集 训练第 2 个学习器
根据预测结果找一个错误率最小的分裂点计算、更新:样本权重、模型权重
- 迭代训练在前一个学习器的基础上,根据新的样本权重训练当前学习器
直到训练出 m 个弱学习器
- m个弱学习器集成预测公式:
𝑎𝑖 为模型的权重,输出结果大于 0 则归为正类,小于 0 则归为负类。
- 模型权重计算公式:
-
样本权重计算公式:
举例构建过程
构建第一个弱分类器
计算最小错误率
第一轮更新权重
一轮更新后
构建第二个弱分类器
最终结果
案例-葡萄酒数据集
# 导包
import pandas as pd
from sklearn.preprocessing import LabelEncoder, StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier # 单个决策树(默认CART)
from sklearn.ensemble import AdaBoostClassifier # 集成学习
# 定义函数实现葡萄酒集成学习
def dm01_adaboost():
# 数据读取
data = pd.read_csv('data/wine0501.csv')
# data.info()
# 数据基本处理
# 去除标签多余类
data = data[data['Class label'] != 1]
# 划分特征和标签
x = data.iloc[:, 1: -1]
# x = data[['Alcohol', 'Hue']]
y = data['Class label'].copy()
# 特征工程
# 标签转化(2, 3) => (0, 1)
y = LabelEncoder().fit_transform(y)
# print(x)
# print(y)
# 划分训练集和测试集
x_train, x_test, y_train, y_test = train_test_split(
x, y,
test_size=0.2,
stratify=y,
random_state=21
)
# 标准化数据集
transfer = StandardScaler()
x_train = transfer.fit_transform(x_train)
x_test = transfer.transform(x_test)
# print(len(x_train))
# print(len(x_test))
# 模型训练
decision_model = DecisionTreeClassifier() # 单一决策树
decision_model.fit(x_train, y_train)
adaboost_model = AdaBoostClassifier(
n_estimators=200,
estimator=decision_model,
learning_rate=0.2 # 给多个基学习器 加权 Lr=0.2
)
"""
此处的学习率 != 梯度下降的学习率
学习率源码解释:
Weight applied to each regressor at each boosting iteration. A higher
learning rate increases the contribution of each regressor. There is
a trade-off between the `learning_rate` and `n_estimators` parameters.
Values must be in the range `(0.0, inf)`.
在每次提升迭代中应用于每个回归变量的权重。更高的
学习率会增加每个回归变量的贡献。有
'learning_rate' 和 'n_estimators' 参数之间的权衡。
值必须在 '(0.0, inf) ' 范围内。
"""
adaboost_model.fit(x_train, y_train)
# 模型评估
print('decision_model:', decision_model.score(x_test, y_test))
print('adaboost_model:', adaboost_model.score(x_test, y_test))
if __name__ == '__main__':
dm01_adaboost()
总结
Adaboost概念
通过逐步提高被分类错误的样本的权重
来训练一个强分类器。提升的思想
Adaboost构建过程
1 初始化数据权重,来训练第1个弱学习器。找最小的错误率计算模型权重
,再更新模型和数据权重。2 根据更新的数据集权重,来训练第2个弱学习器
,再找最小的错误率计算模型权重,再更新模数据权重。3 依次重复第2步,训练n个弱学习器。组合起来进行预测
。结果大于0为正类、结果小于0为负类
四..GBDT
提升树
思想通过拟合残差的思想来进行提升残差:真实值 - 预测值
通过拟合残差可将多个弱学习器组成一个强学习器,这就是提升树的最朴素思想
梯度提升树
梯度提升树 (Gradient Boosting Decision Tree => GBDT)梯度提升树不再拟合残差,而是利用梯度下降的近似方法,利用损失函数的负梯度作为提升树算法中的残差近似值。
GBDT 拟合的负梯度就是残差。如果我们的 GBDT 进行的是分类问题,则损失函数变为 logloss,此时拟合的目标值就是该损失函数的负梯度值
案例解释梯度提升树
构建第一棵弱学习树
构建第一棵弱学习树流程
-
切分点: 相邻点的平均值
-
R1, R2
-
计算左右子树的均值
-
计算平方损失
-
平方损失最小的切分点为 分裂点
-
构建左右子树的均值
构建第二棵弱学习树
构建第二棵若学习树的流程
-
以第一棵弱学习树的
负梯度当作目标值
-
以前一棵若学习树的左右子树的
平均负梯度当作预测值
-
重复构建第一棵弱学习树的步骤
构建结果
整体构建流程
-
初始化弱学习器(目标值的均值作为预测值)
-
迭代构建学习器,每一个学习器拟合上一个学习器的负梯度
-
直到达到指定的学习器个数
-
当输入未知样本时,将所有弱学习器的输出结果组合起来作为强学习器的输出
案例-泰坦尼克数据集
# 导包
import pandas as pd
from sklearn.model_selection import train_test_split, GridSearchCV
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import GradientBoostingClassifier # GBDT
from sklearn.metrics import accuracy_score
# 定义随机森立函数
def dm01_GBDT_classifier():
# 数据读取
data = pd.read_csv('data/train.csv')
data.info()
# 数据基本处理
# 确定特征和标签
x = data.iloc[:, 2:-2].copy()
x.drop(['Name', 'Ticket'], inplace=True, axis='columns')
y = data.Survived
# print(x)
# print(y)
# 空值处理(填充)
x.Age = x.Age.fillna(x.Age.mean())
# print(x)
# 处理字符类型 数据
x = pd.get_dummies(x)
x.drop('Sex_female', inplace=True, axis=1)
# print(x.head())
# 数据划分
x_train, x_test, y_train, y_test = train_test_split(
x, y,
test_size=0.2,
random_state=21,
stratify=y
)
# 模型训练
# 单一决策树模型
model1 = DecisionTreeClassifier()
model1.fit(x_train, y_train)
# GBDT
model2 = GradientBoostingClassifier(max_depth=6)
model2.fit(x_train, y_train)
# 模型评估
print('(决策树)预测后评估:', accuracy_score(y_true=y_test, y_pred=model1.predict(x_test)))
print('(GBDT)预测后评估:', accuracy_score(y_true=y_test, y_pred=model2.predict(x_test)))
# 交叉验证网格搜索, 寻找最优超参数
estimator = GradientBoostingClassifier()
param = {'n_estimators': [100, 200, 300, 400, 500, 600, 700],
'max_depth': [1, 2, 3, 4, 5, 6, 7, 8, 9],
'learning_rate': [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
}
grid_search = GridSearchCV(estimator, param_grid=param, cv=5)
grid_search.fit(x_train, y_train)
print('(交叉验证后)预测后评估:', accuracy_score(y_true=y_test, y_pred=grid_search.best_estimator_.predict(x_test)))
if __name__ == '__main__':
dm01_GBDT_classifier()
总结
提升树
每一个弱学习器通过拟合残差来构建强学习器
梯度提升树
每一个弱学习器通过拟合负梯度来构建强学习器
五. XGBoost
XGBoost算法的思想
XGBoost (eXtreme Gradient Boosting)极端梯度提升树,集成学习方法的王牌,在数据挖掘比赛中,大部分获胜者用了XGBoost。
XGBoost的构建思想
-
构建模型的方法时最小化训练数据的损失函数
上述公式训练模型复杂度较高, 容易过拟合
-
XGBoost极端提升树, 在上述的损失函数基础上加入正则化项, 提高对未知的测数据的泛化性能
-
正则化项用来降低模型的复杂度
γT 中的T表示一棵树的叶子节点数量
λ||w||²中的w表示叶子节点输出值组成的向量, ||w||表示向量的模,
λ表示对该项的调节系数
举例说明正则化项
正则化项 = 树 的复杂度 = 模型的复杂度
假设我们要 预测一家人对电子游戏的喜好程度,考虑到年轻和年老相比,年轻更可能喜欢电子游戏,以及男性和女性相比,男性更喜欢电子游戏,故先根据年龄大小区分小孩和大人,然后再通过性别区分开是男是女,逐一给各人在电子游戏喜好程度上打分
XGBoost目标函数推导
推导图解
分裂依据
根据上述图片中计算的Gain值:
-
对树中的每个叶子结点尝试进行分裂
-
计算分裂前 - 分裂后的分数:
-
如果Gain > 0,则分裂之后树的损失更小,会考虑此次分裂
-
如果Gain< 0,说明分裂后的分数比分裂前的分数大,此时不建议分裂
-
-
当触发以下条件时停止分裂:
-
达到最大深度
-
叶子结点数量低于某个阈值
-
所有的结点在分裂不能降低损失, 等等..
-
XGBoost的算法API
XGBoost的安装和使用
XGBoost的编码风格在sklean机器学习库中没有集成XGBoost。想要使用XGBoost,需要手工安装 pip3 install xgboost 可以在XGBoost的官网上查看最新版本:XGBoost Documentation --- xgboost 2.1.1 documentation
XGBoost的编码风格
支持非sklearn方式,也即是自己的风格支持sklearn方式,调用方式保持sklearn的形式