一、集成学习概念
(一)定义
集成学习(Ensemble Learning)是一种通过构建并结合多个模型(学习器)来完成学习任务的机器学习范式,目的是获得更好的泛化性能。
核心思想:多个模型的集体智慧通常比单个模型更准确、更鲁棒(多个弱学习器组合成一个强学习器)。
(二)集成学习分类
1. Bagging
思想:通过有放回的抽样产生不同的训练集,训练不同的学习器,然后通过平权投票或者多数表决的方式决定预测结果。弱学习器可以并行训练。
注意:训练集是有放回的抽样,不是将其均分,每一份都有可能会存在重复的数据。
代表算法:随机森林
2. Boosting
思想:在全部样本中,每一个训练器重点关注前一个训练器不足的地方进行训练,通过加权投票的方式提出预测结果,采用串行的训练方式。
代表算法:Adaboost、GBDT、XGBoost、LightGBM
3. Bagging和Boosting比较
二、集成学习方法
(一)核心对比
(二)详细对比
1. Bagging
如:随机森林
训练时:通过“有放回”的自主采样(bootstrap)从训练集中生成多个子集,每个子集“独立”训练一个基学习器(如决策树)。
预测时:所有基学习器对未知样本进行预测,最终结果过投票(分类)或平均(回归)得到
API:sklearn.ensemble.RandomForestClassifier
2. Boosting
如:Adaboost、GBDT、XGBoost
训练时:基学习器是顺序训练的,每个新模型都试图修正前一个模型的错误(如调整样本权重或拟合残差)。
预测时:所有基学习器的预测结果进行加权组合(如Adaboost)或累加(GBDT系列)。
API:sklearn.ensemble.AdaBoostClassifier
sklearn.ensemble.GradientBoostingClassifier
from xgboost import XGBClassifier(分类问题)
from xgboost import XGBRegressor(回归问题)
3. Stacking(了解)
训练时:先训练不同类型的基学习器,再用它们的输出训练一个元学习器(meta-model)。
预测时:基学习器先预测,然后元学习器基于它们的输出做最终预测。
三、底层原理
(一)Bagging(并行训练)
Bagging 是通过自助采样(Bootstrap Sampling)来构建多个基学习器。它从原始数据集中有放回地抽取样本,形成多个新的训练数据集。每个新的数据集都用于训练一个基学习器。例如,对于一个包含100个样本的数据集,Bagging 方法可能会抽取100个样本(允许重复)来形成一个新的训练数据集,然后用这个数据集训练一个基学习器。这样重复多次,得到多个基学习器。
在预测阶段,对于分类问题,Bagging通过多数投票的方式确定最终的预测结果;对于回归问题,通过取基学习器预测结果的平均值来确定最终结果。
一句话概述:多个模型独立训练,投票决定结果(稳)
典型算法 - 随机森林(Random Forest)
随机森林 是在 Bagging 的基础上发展起来的。它在构建基学习器(通常是决策树)时,除了对样本进行自助采样外,还会在特征选择上进行随机性处理。在每次分裂决策树的节点时,随机森林不会考虑所有的特征,而是从所有特征中随机选择一部分特征,然后在这部分特征中选择最优的特征进行分裂。这增加了基学习器之间的差异性,进一步提高了模型的性能。
步骤:①有放回的随机抽样产生训练集
②随机挑选n个特征(n<特征总数)
③训练弱学习器
④重复1-3,训练n个弱学习器(决策树)
⑤预测结果:分类问题(多数表决);回归问题(计算平均值)
随机森林具有很强的泛化能力,广泛应用于图像识别、文本分类等领域。
代码实现--泰坦尼克号生存预测概率
# 1、导入模块
import pandas as pd
from sklearn.model_selection import train_test_split
# 2、加载数据
data = pd.read_csv('../../day06_决策树/data/train.csv')
# 了解数据
data.info()
print(data.head())
print(data.columns)
# 3、特征工程
x = data[['Pclass', 'Age', 'Sex']]
y = data['Survived']
# x['Age']=x['Age'].fillna(x['Age'].mean(), inplace=True)
x['Age'] = x['Age'].fillna(x['Age'].mean())
# print(f"对年龄进行均值填充后的特征数据:\n{x}")
x = pd.get_dummies(x)
# print(f"对特征数据进行热编码后的结果为:\n{x}")
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=22)
# 4、使用单一决策树进行训练、预测分析
from sklearn.tree import DecisionTreeClassifier
dtc = DecisionTreeClassifier()
dtc.fit(x_train, y_train)
dtc_pred = dtc.predict(x_test)
dtc.score(x_test, y_test)
# 5、使用随机森林进行训练、预测分析
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(max_depth=6, random_state=9)
rfc.fit(x_train, y_train)
rfc_pred = rfc.predict(x_test)
rfc.score(x_test, y_test)
# 6、模型评估
from sklearn.metrics import classification_report
print(f'决策树的相关报表结果:\n{classification_report(dtc_pred, y_test)}')
print(f'随机森林的相关报表结果:\n{classification_report(rfc_pred, y_test)}')
(二)Boosting(串行训练)
Boosting 是一种逐步改进模型性能的方法。它将基学习器按照一定的顺序组合起来,后面的基学习器会根据前面基学习器的预测结果来调整训练数据的权重。对于前面基学习器预测错误的样本,会增加其权重,让后面的基学习器更加关注这些样本。例如,在第一轮训练后,如果某些样本被错误分类,那么在下一轮训练时,这些样本的权重会增大,使得新的基学习器更加专注于这些“难分类”的样本。
Boosting 最终的模型是将所有基学习器的预测结果加权求和来确定最终结果。每个基学习器的权重是根据它的性能来确定的,性能好的基学习器在最终模型中所占的权重更大。
一句话概述:模型逐步改进,加权组合结果(准)
典型算法 - AdaBoost(Adaptive Boosting)
AdaBoost是最经典的Boosting算法。它通过调整样本权重来训练一系列弱学习器(通常是简单的模型,如单层决策树)。在每一轮训练中,它计算每个弱学习器的错误率,并根据错误率来更新样本权重和确定弱学习器的权重。对于错误率低的弱学习器,会赋予较大的权重。AdaBoost在二分类问题上表现出色,如在生物医学图像分析中用于细胞分类等任务。
算法思想:通过逐步提高前一步分类错误的样本的权重来训练一个强分类器
步骤:①初始化数据权重,训练第一个学习器,根据预测结果找一个错误率最小的分裂点,然后重新计算样本权重,模型权重;②根据新的样本权重,训练第二个学习器,根据结果找一个错误率最小的分裂点,然后再次更新样本权重,模型权重(注:样本权重的变化,影响了错误率的计算,进而影响了模型权重的计算,所以随着训练的展开,模型会越来越关注分类错误的样本);③重复以上过程,依次训练n个学习器,最终组合起来进行预测,结果大于0为正类,小于0为负类
代码实现--AdaBoost实战葡萄酒数据
import pandas as pd
# 读取葡萄酒数据集
data = pd.read_csv('../data/wine0501.csv')
# print(data.columns)
"""
Index(['Class label', 'Alcohol', 'Malic acid', 'Ash', 'Alcalinity of ash',
'Magnesium', 'Total phenols', 'Flavanoids', 'Nonflavanoid phenols',
'Proanthocyanins', 'Color intensity', 'Hue',
'OD280/OD315 of diluted wines', ' Proline'],
dtype='object')
"""
# 去掉'Class label'特征中的1类
data = data[data['Class label'] != 1]
# print(data)
# 提取'Alcohol'和'Hue'特征作为输入变量,'Class label'作为目标变量
x = data[['Alcohol', 'Hue']].values
y = data['Class label'].values
from sklearn.preprocessing import LabelEncoder
from sklearn.model_selection import train_test_split
# 类别转换(2,3)-->(0,1)
leibie = LabelEncoder()
y = leibie.fit_transform(y)
# 分割数据集为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(x, y, test_size=0.3, random_state=1)
from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import AdaBoostClassifier
# 机器学习(决策树和AdaBoost)
# 初始化决策树分类器
tree = DecisionTreeClassifier(criterion='entropy', max_depth=1, random_state=0)
# 初始化AdaBoost分类器,使用决策树作为基础估计器
ada = AdaBoostClassifier(estimator=tree, n_estimators=500, learning_rate=0.1, random_state=0)
from sklearn.metrics import accuracy_score
# 训练决策树模型
tree = tree.fit(X_train, y_train)
# 预测训练集和测试集
y_train_pred = tree.predict(X_train)
y_test_pred = tree.predict(X_test)
# 计算准确率
tree_train = accuracy_score(y_train, y_train_pred)
tree_test = accuracy_score(y_test, y_test_pred)
print(f'决策树训练集的准确率为:{tree_train}')
print(f'决策树测试集的准确率为:{tree_test}')
# AdaBoost 性能评估
# 训练AdaBoost模型
ada.fit(X_train, y_train)
# 预测训练集和测试集
ada_train_pred = ada.predict(X_train)
ada_test_pred = ada.predict(X_test)
# 计算准确率
ada_train = accuracy_score(y_train, ada_train_pred)
ada_test = accuracy_score(y_test, ada_test_pred)
print(f'AdaBoost训练集的准确率为:{ada_train}')
print(f'AdaBoost测试集的准确率为:{ada_test}')
典型算法 - GBDT(Gradient Boosting Decision Tree)梯度提升树
GBDT 通过迭代的方式拟合前一轮模型的残差(即真实值与当前模型预测值的差异),逐步提升模型的精度。每一轮新模型的目标是拟合前一轮模型的残差,最终将所有弱学习器的预测结果叠加,形成强学习器。
步骤:①初始化弱学习器:通常以目标值的均值作为初始预测值;②迭代构建学习器:在每一轮迭代中,计算当前模型的残差,然后训练一个新的弱学习器(通常是决策树)来拟合这些残差;③更新模型:将新训练的弱学习器加入到模型中,更新模型的预测结果;④重复步骤2和3:直到达到指定的学习器个数或模型性能不再提升;⑤最终预测:当输入未知样本时,将所有弱学习器的输出结果组合起来作为强学习器的输出。
代码实现--泰坦尼克号案例
# 1、导入模块
import pandas as pd
from sklearn.model_selection import train_test_split
# 2、加载数据
data = pd.read_csv('../../day06_决策树/data/train.csv')
# 了解数据
data.info()
print(data.head())
print(data.columns)
# 3、特征工程
x = data[['Pclass', 'Age', 'Sex']].copy() # 提取特征并复制一份副本避免警告
y = data['Survived']
# 缺失值处理,使用平均年龄填充缺失的年龄值
x['Age'] = x['Age'].fillna(x['Age'].mean())
# 数据划分,将数据划分为训练集和测试集,测试集占比25%
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.25, random_state=22)
# 将数据转化为特征向量
# 导入DictVectorizer用于将字典形式的数据转换为特征向量
from sklearn.feature_extraction import DictVectorizer
# 初始化DictVectorizer对象,不生成稀疏矩阵
vec = DictVectorizer(sparse=False)
# 将训练集特征转换为数值型特征向量
x_train = vec.fit_transform(x_train.to_dict(orient='records'))
# 将测试集特征使用训练集fit的信息进行转换
x_test = vec.transform(x_test.to_dict(orient='records'))
# 4、使用单一决策树进行训练、预测分析
# 5、使用随机森林进行训练、预测分析
from sklearn.ensemble import RandomForestClassifier
rfc = RandomForestClassifier(random_state=9)
rfc.fit(x_train, y_train)
rfc_pred = rfc.predict(x_test)
print("随机森林模型的准确率:", rfc.score(x_test, y_test))
# 6、GBDT模型进行训练、预测分析
from sklearn.ensemble import GradientBoostingClassifier # 导入梯度提升决策树(GBDT)分类器
gbc = GradientBoostingClassifier()
gbc.fit(x_train, y_train)
gbc_pred = gbc.predict(x_test)
print("GBDT模型的准确率:", gbc.score(x_test, y_test))
# 7、模型评估
from sklearn.metrics import classification_report
# 输出分类报告(包括精确率、召回率、F1分数等指标)
print(f'随机森林的相关报表结果:\n{classification_report(rfc_pred, y_test)}')
print(f'GBDT模型的相关报表结果:\n{classification_report(gbc_pred, y_test)}')
典型算法 - XGBoost(Extreme Gradient Boosting)极端梯度提升树
XGBoost在GBDT的基础上进行了优化,通过在损失函数中加入正则化项来防止过拟合,同时引入了泰勒二阶展开来近似损失函数,提高了模型的训练效率和泛化能力。XGB 自创一个树节点分裂指标。这个分裂指标就是从损失函数推导出来的。XGB 分裂树时考虑到了树的复杂度。构建最优模型的方法是最小化训练数据的损失函数。
步骤:①初始化弱学习器:通常以目标值的均值作为初始预测值。②迭代构建学习器:在每一轮迭代中,计算当前模型的损失函数的一阶导数(梯度)和二阶导数,然后训练一个新的弱学习器(通常是决策树)来拟合这些梯度。③更新模型:将新训练的弱学习器加入到模型中,更新模型的预测结果。更新时会考虑正则化项,以控制模型的复杂度。④重复步骤2和3:直到达到指定的学习器个数或模型性能不再提升。⑤最终预测:当输入未知样本时,将所有弱学习器的输出结果组合起来作为强学习器的输出。
代码实现--红酒品质预测案例
# 1、导包
import joblib
import pandas as pd
from sklearn.model_selection import train_test_split
# 导入xgb模块
import xgboost as xgb
from sklearn.metrics import classification_report
# 2、加载数据
data = pd.read_csv('../data/红酒品质分类.csv')
# 3、了解数据
print(data.head())
data.info()
# 4、 数据预处理,提取特征值和目标值
x = data.iloc[:, :-1]
y = data.iloc[:, -1] - 3 # 选取data最后一列的所有行数据,然后将这些值减去 3
# 5、数据集划分
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2, random_state=22, stratify=y)
# stratify=y 保证训练集和测试集中各类别的比例与原数据一致
# 数据存储
pd.concat([x_train, y_train], axis=1).to_csv('data/红酒品质分类_train.csv', index=False)
pd.concat([x_test, y_test], axis=1).to_csv('data/红酒品质分类_test.csv', index=False)
print('===============================================================================')
# 加载存储的数据
train_data = pd.read_csv('data/红酒品质分类_train.csv')
test_data = pd.read_csv('data/红酒品质分类_test.csv')
x_train = train_data.iloc[:, :-1]
y_train = train_data.iloc[:, -1]
x_test = test_data.iloc[:, :-1]
y_test = test_data.iloc[:, -1]
print(x_train.shape, y_train.shape, x_test.shape, y_test.shape)
# 创建xgb模型
model = xgb.XGBClassifier(objective='multi:softmax')
"""
objective 指定模型训练的目标函数,例如:
reg:squarederror:回归任务,使用均方误差。
binary:logistic:二分类任务,输出概率。
multi:softmax:多分类任务,输出类别标签
"""
# xgb模型训练
model.fit(x_train, y_train)
# xgb模型评估
print(f'准确率:{model.score(x_test, y_test)}')
y_pred = model.predict(x_test)
print(f"模型评估报告:\n{classification_report(y_test, y_pred)}")
# 模型保存
# joblib.dump(model, 'model/xgboost_model.pkl')