问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

LightGBM+XGBoost:汽车燃油效率预测的集成学习方案

创作时间:
2025-01-21 21:43:10
作者:
@小白创作中心

LightGBM+XGBoost:汽车燃油效率预测的集成学习方案

梯度提升集成是一种强大的机器学习技术,通过结合多个模型的预测结果来提高预测的准确性和稳定性。本文将详细介绍如何使用LightGBM和XGBoost进行梯度提升集成预测,以汽车燃油效率数据集(Auto MPG)为例,展示从数据预处理到模型评估的完整流程。

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

代码实现流程图

代码实现

数据读取

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

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

缺失值处理

df.isnull().sum()

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()

数据集划分

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}")

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

归一化目标变量

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)

定义和训练模型

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)

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

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

预测测试集

y_pred = average_model.predict(X_test)
y_pred

计算评估指标

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)

可视化预测结果

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()

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

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号