梯度提升集成:LightGBM与XGBoost组合预测

技术

LightGBM和XGBoost是两种高效的梯度提升决策树算法,常用于回归和分类任务,通过逐步优化模型来提升预测精度,并支持并行计算以加速训练过程,我们的组合模型通过分别训练LightGBM和XGBoost模型,然后对它们的预测结果取平均值,以进一步提高预测的准确性和稳健性

1. 代码实现流程图

picture.image

2. 代码实现

2.1 数据读取


          
import pandas as pd
          
df = pd.read_excel('Auto MPG.xlsx')
          
df.head()
      

picture.image

数据涉及城市循环燃油消耗,以每加仑英里数 (miles per gallon, mpg) 为单位,根据 3 个多值离散属性和 5 个连续属性来预测mpg

2.2 缺失值处理


        
            

          df.isnull().sum()
        
      

picture.image

horsepower列存在6条缺失值,采用基于K最近邻的缺失值填充算法,假设相似的样本在特征空间中具有相似的特征值,从而使得填充后的数据尽可能保持原有的分布特性


          
# 采用KNN算法填补缺失值
          
from sklearn.impute import KNNImputer
          
imputer = KNNImputer(n_neighbors=3)
          
imputed = imputer.fit_transform(df)
          
data = pd.DataFrame(imputed, columns=df.columns, index = df.index)
          
data.isnull().sum()
      

2.3 数据集划分


          
from sklearn.model_selection import train_test_split
          

          
# 首先将数据集划分为训练集和测试集
          
X_temp, X_test, y_temp, y_test = train_test_split(df.iloc[:,0:7], df['mpg'], test_size=0.2, random_state=42)
          

          
# 然后将训练集进一步划分为训练集和验证集
          
X_train, X_val, y_train, y_val = train_test_split(X_temp, y_temp, test_size=0.125, random_state=42)  # 0.125 x 0.8 = 0.1
          

          
# 输出数据集的大小
          
print(f"训练集维度: {X_train.shape}")
          
print(f"验证集维度: {X_val.shape}")
          
print(f"测试集维度: {X_test.shape}")
      

picture.image

函数train_test_split函数是可以直接进行数据集的训练集和测试集分割的,然而,它不能直接将数据分为训练集、验证集和测试集三部分,于是利用函数对数据集进行两次分割,首先将数据划分为训练集和测试集,然后将训练集进一步分割为训练集和验证集,并保证训练集、验证集、测试集的比例约为7:1:2

2.4 归一化目标变量


          
from sklearn.preprocessing import MinMaxScaler
          

          
def normalize_dataframe(y_train, y_val, y_test):
          
    scaler = MinMaxScaler()
          
    scaler.fit(np.array(y_train).reshape(-1, 1))  # 在训练集上拟合归一化模型 MinMaxScaler输入数据形状为二维数组
          
    
          
    train = pd.DataFrame(scaler.transform(np.array(y_train).reshape(-1, 1)), index=y_train.index)
          
    val = pd.DataFrame(scaler.transform(np.array(y_val).reshape(-1, 1)), index=y_val.index)
          
    test = pd.DataFrame(scaler.transform(np.array(y_test).reshape(-1, 1)), index=y_test.index)
          
    
          
    return train, val, test, scaler
          

          
train_y, val_y, test_y, scaler_y = normalize_dataframe(y_train, y_val, y_test)
      

2.5 定义和训练模型


          
import lightgbm as lgb
          
import xgboost as xgb
          

          
# LightGBM模型参数
          
params_lgb = {
          
    'learning_rate': 0.02,          # 学习率,控制每一步的步长,用于防止过拟合。典型值范围:0.01 - 0.1
          
    'boosting_type': 'gbdt',        # 提升方法,这里使用梯度提升树(Gradient Boosting Decision Tree,简称GBDT)
          
    'objective': 'mse',             # 损失函数
          
    'metric': 'rmse',               # 评估指标
          
    'num_leaves': 127,              # 每棵树的叶子节点数量,控制模型复杂度。较大值可以提高模型复杂度但可能导致过拟合
          
    'verbose': -1,                  # 控制 LightGBM 输出信息的详细程度,-1表示无输出,0表示最少输出,正数表示输出更多信息
          
    'seed': 42,                     # 随机种子,用于重现模型的结果
          
    'n_jobs': -1,                   # 并行运算的线程数量,-1表示使用所有可用的CPU核心
          
    'feature_fraction': 0.8,        # 每棵树随机选择的特征比例,用于增加模型的泛化能力
          
    'bagging_fraction': 0.9,        # 每次迭代时随机选择的样本比例,用于增加模型的泛化能力
          
    'bagging_freq': 4               # 每隔多少次迭代进行一次bagging操作,用于增加模型的泛化能力
          
}
          
model_lgb = lgb.LGBMRegressor(**params_lgb)
          

          
# XGBoost模型参数
          
params_xgb = {
          
    'learning_rate': 0.02,          # 学习率,控制每一步的步长,用于防止过拟合。典型值范围:0.01 - 0.1
          
    'booster': 'gbtree',            # 提升方法,这里使用梯度提升树(Gradient Boosting Tree)
          
    'objective': 'reg:squarederror',# 损失函数
          
    'max_leaves': 127,              # 每棵树的叶子节点数量,控制模型复杂度。较大值可以提高模型复杂度但可能导致过拟合
          
    'verbosity': 1,                 # 控制 XGBoost 输出信息的详细程度,0表示无输出,1表示输出进度信息
          
    'seed': 42,                     # 随机种子,用于重现模型的结果
          
    'nthread': -1,                  # 并行运算的线程数量,-1表示使用所有可用的CPU核心
          
    'colsample_bytree': 0.6,        # 每棵树随机选择的特征比例,用于增加模型的泛化能力
          
    'subsample': 0.7,               # 每次迭代时随机选择的样本比例,用于增加模型的泛化能力
          
    'early_stopping_rounds': None   # 早停参数在fit时单独设置
          
}
          
model_xgb = xgb.XGBRegressor(**params_xgb)
          

          
# 定义平均模型
          
class AverageModel:
          
    def __init__(self, models):
          
        self.models = models
          
        
          
    def fit(self, X, y, X_val, y_val):
          
        for model in self.models:
          
            if isinstance(model, lgb.LGBMRegressor):
          
                model.fit(X, y, eval_set=[(X_val, y_val)], eval_metric='rmse', callbacks=[lgb.early_stopping(stopping_rounds=100)])
          
            elif isinstance(model, xgb.XGBRegressor):
          
                model.fit(X, y, eval_set=[(X_val, y_val)], eval_metric='rmse', early_stopping_rounds=model.get_params()['early_stopping_rounds'], verbose=False)
          
    
          
    def predict(self, X):
          
        predictions = []
          
        for model in self.models:
          
            predictions.append(model.predict(X))
          
        return sum(predictions) / len(predictions)
          

          
# 创建平均模型
          
average_model = AverageModel([model_lgb, model_xgb])
          

          
# 训练模型
          
average_model.fit(X_train, train_y, X_val, val_y)
      

picture.image

代码定义了一个名为 AverageModel 的类,用于创建一个平均模型,通过集成LightGBM和XGBoost模型的预测结果来提升预测的稳定性和准确性,在 fit 方法中,该类可以同时训练传入的多个模型,并使用验证集进行早期停止策略来防止过拟合,在 predict 方法中,该类将多个模型的预测结果取平均作为最终的预测输出

这里代码使用了一个平均模型类,将多个模型包装起来,提供了更统一和可重用的接口,方便管理和使用多个模型,当然也可以考虑引入K折交叉验证在每个fold内部独立训练和评估模型,然后手动取平均预测结果,如果希望封装多个模型为一个整体进行训练和预测,可以使用当前代码的方式,如果需要更灵活的控制和理解每个模型在每个fold的表现,可以采取第二种方法进行代码编写

2.6 预测测试集


          
y_pred = average_model.predict(X_test)
          
y_pred
      

picture.image

2.7 计算评估指标


          
from sklearn import metrics
          
y_pred_list = y_pred.tolist()  # 或者 y_pred_array = np.array(y_pred)
          
mse = metrics.mean_squared_error(test_y, y_pred_list)
          
rmse = np.sqrt(mse)
          
mae = metrics.mean_absolute_error(test_y, y_pred_list)
          
r2 = metrics.r2_score(test_y, y_pred_list)
          

          
print("均方误差 (MSE):", mse)
          
print("均方根误差 (RMSE):", rmse)
          
print("平均绝对误差 (MAE):", mae)
          
print("拟合优度 (R-squared):", r2)
      

picture.image

2.8 可视化预测结果


          
import matplotlib.pyplot as plt
          
plt.rcParams['font.sans-serif'] = 'SimHei'
          
plt.rcParams['axes.unicode_minus'] = False
          
# 反归一化
          
train_min = np.min(y_train)
          
train_max = np.max(y_train)
          
pred = y_pred * (train_max - train_min) + train_min
          
y_test = np.array(y_test)
          
plt.figure(figsize=(8, 8), dpi=300)
          
# 计算预测值 真实值差值的绝对值
          
alpha_values = abs(pred-y_test.reshape(-1))  # 值越大alpha越大
          
# 确保 alpha 值在 0 到 1 之间
          
alpha_values = np.clip(alpha_values, 0, 1)
          
plt.scatter(pred, y_test, color='blue', edgecolor='k', s=50, alpha=alpha_values, label='预测值 vs 真实值')
          
plt.title('预测值与真实值对比图', fontsize=16)
          
plt.xlabel('预测值', fontsize=14)
          
plt.ylabel('真实值', fontsize=14)
          
max_val = max(max(pred), max(y_test))
          
min_val = min(min(pred), min(y_test))
          
plt.plot([min_val, max_val], [min_val, max_val], color='red', linestyle='--', linewidth=2, label='x=y')
          
plt.grid(True, linestyle='--', alpha=0.7)
          
plt.legend()
          
plt.show()
      

picture.image

图中横轴表示模型预测的值,纵轴表示真实的标签值,每个点的透明度(alpha 值)根据预测值与真实值的差异大小动态调整,差异越大的点透明度越低,红色虚线表示理想情况下预测值等于真实值的对角线

3. 往期推荐

时间序列预测:CNN-BiLSTM模型实践

利用python meteostat库对全球气象数据访问,获取历史气象数据

基于LSTM模型的多输入多输出单步时间序列预测

使用LSTM模型预测多特征变量的时间序列

TCN时间序列卷积神经网络

基于VMD分解的VMD-CNN-LSTM时间序列预测模型实现

基于VMD分解的VMD-LSTM时间序列预测模型实现,大力提升预测精度!

长短期记忆网络LSTM在时序数据预测演示

如果你对类似于这样的文章感兴趣。

欢迎关注、点赞、转发~

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论