所有文章 > AI驱动 > 梯度提升集成:CatBoost与NGBoost模型的K折交叉验证及组合预测

梯度提升集成:CatBoost与NGBoost模型的K折交叉验证及组合预测

背景

机器学习和数据科学领域,模型的性能和稳定性是至关重要的,为了提高预测的准确性,通常采用集成学习的方法,将多个模型的预测结果进行组合,梯度提升是一种强大的集成学习方法,通过逐步减小模型的预测误差,提升整体模型的性能,在本文中,我们使用了两种先进的梯度提升模型:CatBoost和NGBoost,CatBoost是一种基于决策树的梯度提升算法,具有处理类别特征、减少过拟合以及高效并行计算的优势,NGBoost是另一种基于自然梯度的方法,能够在保证预测精度的同时提供不确定性估计,为了进一步提升模型的稳健性和泛化能力,我们采用了K折交叉验证的方法,K折交叉验证是一种常用的验证技术,通过将数据集划分为K个子集,并在不同的子集上训练和验证模型,从而有效评估模型的性能和避免过拟合

代码实现

数据读取处理

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split, KFold
from sklearn.metrics import mean_squared_error
from ngboost import NGBRegressor
from catboost import CatBoostRegressor

# 设置字体
plt.rcParams['font.sans-serif'] = 'SimHei'
plt.rcParams['axes.unicode_minus'] = False

# 读取数据
df = pd.read_excel('数据.xlsx')

# 划分特征和目标变量
X = df.drop(['price'], axis=1)
y = df['price']

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

数据预处理中,我们从Excel文件中读取数据,并划分特征和目标变量,与往期代码不同的是,这次我们没有单独划分验证集,因为K折交叉验证会在输入的训练集中自动进行验证划分,这样,整个训练集都被充分利用,提高了模型评估的可靠性,同时我们的测试集保持不变,用于最终的模型评估

模型定义

# CatBoost模型参数
params_cat = {
'learning_rate': 0.02,
'iterations': 1000,
'depth': 6,
'eval_metric': 'RMSE',
'random_seed': 42,
'verbose': 100
}

# NGBoost模型参数
params_ngb = {
'learning_rate': 0.02,
'n_estimators': 1000,
'verbose': False,
'random_state': 42,
'natural_gradient': True
}

# 定义平均模型类
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, NGBRegressor):
model.fit(X, y, X_val=X_val, Y_val=y_val) # NGBoost的fit方法接受验证集参数
elif isinstance(model, CatBoostRegressor):
model.fit(X, y, eval_set=(X_val, y_val), use_best_model=True, verbose=False)

def predict(self, X):
predictions = []
for model in self.models:
predictions.append(model.predict(X))
return sum(predictions) / len(predictions)

定义CatBoost和NGBoost模型的参数,并通过一个名为AverageModel的类来训练这些模型,该类在训练时根据不同模型调用相应的fit方法并在预测时平均所有模型的预测结果,当然也可以改进组合策略在预测时通过不同的策略(如加权平均、投票等)综合所有模型的预测结果

k折交叉验证下训练模型

# 定义k折交叉验证
kf = KFold(n_splits=5, shuffle=True, random_state=42)
scores = []
best_score = float('inf')
best_model = None

# 进行k折交叉验证
for fold, (train_index, val_index) in enumerate(kf.split(X_train, y_train)):
X_train_fold, X_val_fold = X_train.iloc[train_index], X_train.iloc[val_index]
y_train_fold, y_val_fold = y_train.iloc[train_index], y_train.iloc[val_index]

# 计算当前训练集的均值和标准差
x_mean_fold = X_train_fold.mean()
x_std_fold = X_train_fold.std()
y_mean_fold = y_train_fold.mean()
y_std_fold = y_train_fold.std()

# 标准化
X_train_fold = (X_train_fold - x_mean_fold) / x_std_fold
y_train_fold = (y_train_fold - y_mean_fold) / y_std_fold
X_val_fold = (X_val_fold - x_mean_fold) / x_std_fold
y_val_fold = (y_val_fold - y_mean_fold) / y_std_fold

# 创建和训练组合模型
current_model = AverageModel([NGBRegressor(**params_ngb), CatBoostRegressor(**params_cat)])
current_model.fit(X_train_fold, y_train_fold, X_val_fold, y_val_fold)

# 预测并计算得分
y_val_pred = current_model.predict(X_val_fold)
score = mean_squared_error(y_val_fold * y_std_fold + y_mean_fold, y_val_pred * y_std_fold + y_mean_fold, squared=False) # 反标准化得分

scores.append(score)
print(f'Fold {fold + 1} RMSE: {score}')

# 保留得分最好的模型
if score < best_score:
best_score = score
best_model = current_model

print(f'Best RMSE: {best_score}')

定义了5折交叉验证,通过对每折的训练集和验证集进行标准化后训练NGBRegressor和CatBoostRegressor组合模型,并在每折计算验证集的RMSE来评估模型性能,最终选出得分最好的模型作为最佳模型

模型预测

# 使用最佳模型进行测试集预测
x_mean_final = X_train.mean()
x_std_final = X_train.std()
X_test_standardized = (X_test - x_mean_final) / x_std_final
y_test_standardized = (y_test - y.mean()) / y.std()
y_test_pred_standardized = best_model.predict(X_test_standardized)
y_test_pred = y_test_pred_standardized * y.std() + y.mean()
# 输出反标准化后的预测结果
results = pd.DataFrame({'Actual': y_test, 'Predicted': y_test_pred})

使用训练集的均值和标准差对测试集进行标准化,并用最佳模型预测测试集的目标值,再将预测结果反标准化以输出实际值和预测值的比较

详细评价指标

from sklearn import metrics
import numpy as np
y_pred_list = y_test_pred.tolist() # 或者 y_pred_array = np.array(y_pred)
mse = metrics.mean_squared_error(y_test, y_pred_list)
rmse = np.sqrt(mse)
mae = metrics.mean_absolute_error(y_test, y_pred_list)
r2 = metrics.r2_score(y_test, y_pred_list)
print("均方误差 (MSE):", mse)
print("均方根误差 (RMSE):", rmse)
print("平均绝对误差 (MAE):", mae)
print("拟合优度 (R-squared):", r2)

可视化对比

# 可视化 results 数据框
plt.figure(figsize=(10, 6), dpi=300)
plt.scatter(results['Predicted'], results['Actual'], color='blue', edgecolor='k', s=50, alpha=0.6, label='预测值 vs 真实值')
plt.title('预测值与真实值对比图', fontsize=16)
plt.xlabel('预测值', fontsize=14)
plt.ylabel('真实值', fontsize=14)
max_val = max(results.max())
min_val = min(results.min())
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()

本文章转载微信公众号@Python机器学习AI