使用Scikit-learn训练HistGradientBoostingRegressor
使用Scikit-learn训练HistGradientBoostingRegressor
引言
在机器学习回归任务中,梯度提升树(Gradient Boosting Tree)一直以其优异的性能备受青睐。Scikit-learn 在 0.21 版本中引入了两种基于直方图的梯度提升树实现——HistGradientBoostingClassifier 和 HistGradientBoostingRegressor,其灵感来源于知名的 LightGBM 框架。本文将详细介绍如何使用 HistGradientBoostingRegressor 进行回归建模。
为什么选择 HistGradientBoostingRegressor?
与传统的 GradientBoostingRegressor 相比,HistGradientBoostingRegressor 在大数据集上有着显著的性能优势:
- 速度优势:对于样本量达到 10,000 以上的数据集,该估计器比
GradientBoostingRegressor快得多。其核心思想是将输入数据预先分箱(binning)为整数值,大幅减少了需要考察的分裂点数量。 - 原生支持缺失值:该估计器原生支持缺失值(NaN),在训练过程中会自动学习缺失值样本应该被分配到左子节点还是右子节点。
- 支持分类特征:可以直接处理分类特征,无需手动进行 One-Hot 编码。
- 支持单调约束:可以对特征施加单调性约束,满足某些业务场景的需求。
不过需要注意的是,对于小样本数据集(如几百个样本),传统的 GradientBoostingRegressor 可能更合适,因为分箱操作在小样本下可能导致分裂点过于粗糙。
导入与基本使用
在 Scikit-learn 1.0 之前的版本中,HistGradientBoostingRegressor 属于实验性功能,需要显式导入 enable_hist_gradient_boosting。从 Scikit-learn 1.0 开始,该功能已正式稳定,可以直接导入使用。
# 直接导入(推荐,适用于 Scikit-learn 1.0+)
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.datasets import make_regression
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error
# 生成示例数据
X, y = make_regression(n_samples=10000, n_features=20, noise=0.1, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# 创建并训练模型
model = HistGradientBoostingRegressor(random_state=42)
model.fit(X_train, y_train)
# 预测与评估
y_pred = model.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
print(f"测试集 MSE: {mse:.4f}")
核心参数详解
HistGradientBoostingRegressor 提供了丰富的参数供调优:
1. 损失函数(loss)
指定 boosting 过程中使用的损失函数,可选值包括:
| 参数值 | 说明 |
|---|---|
'squared_error' |
平方误差(默认),适用于大多数回归任务 |
'absolute_error' |
绝对误差,对异常值更鲁棒 |
'gamma' |
Gamma 偏差,要求目标值 y > 0(1.3 版本新增) |
'poisson' |
Poisson 偏差,要求目标值 y >= 0(0.23 版本新增) |
'quantile' |
分位数损失,需配合 quantile 参数使用(1.1 版本新增) |
# 使用分位数损失预测 0.9 分位数
model = HistGradientBoostingRegressor(loss='quantile', quantile=0.9)
2. 学习率(learning_rate)
默认为 0.1,作为叶子节点值的乘法因子(即收缩因子)。较小的学习率通常需要更多的树来达到好的效果。
3. 树的数量(max_iter)
默认为 100,即 boosting 过程的最大迭代次数,也就是树的最大数量。
4. 树的复杂度控制
max_leaf_nodes:每棵树的最大叶子节点数,默认为 31。max_depth:每棵树的最大深度,默认为 None(不限制)。min_samples_leaf:每个叶子节点的最小样本数,默认为 20。对于小数据集(几百个样本),建议降低此值。
5. 正则化(l2_regularization)
L2 正则化参数,默认为 0。增大该值可以防止过拟合。
6. 分箱参数(max_bins)
用于非缺失值的最大分箱数量,默认为 255。每个特征在训练前会被分箱为整数值,这大大加快了训练速度。该值不能大于 255。
7. 提前停止(early_stopping)
默认为 'auto'——当样本量大于 10,000 时自动启用提前停止。配合以下参数使用:
validation_fraction:验证集比例,默认为 0.1n_iter_no_change:验证集得分连续 n 次不提升时停止训练,默认为 10tol:判断是否提升的容忍度,默认为 1e-7
model = HistGradientBoostingRegressor(
max_iter=1000,
early_stopping=True,
validation_fraction=0.1,
n_iter_no_change=10,
random_state=42
)
完整示例:使用网格搜索调优
以下是一个使用加州房价数据集进行网格搜索调优的完整示例:
from sklearn.datasets import fetch_california_housing
from sklearn.ensemble import HistGradientBoostingRegressor
from sklearn.model_selection import GridSearchCV, cross_validate, KFold
from sklearn.metrics import mean_squared_error, r2_score
import numpy as np
# 加载数据
data, target = fetch_california_housing(return_X_y=True, as_frame=True)
target *= 100 # 将目标值调整为千美元单位
# 创建模型(设置较大的 max_iter,配合 early_stopping)
hist_gbdt = HistGradientBoostingRegressor(
max_iter=1000,
early_stopping=True,
random_state=0
)
# 定义参数网格
params = {
"max_depth": [3, 8],
"max_leaf_nodes": [15, 31],
"learning_rate": [0.1, 1],
}
# 网格搜索
search = GridSearchCV(hist_gbdt, params, cv=3, scoring='r2')
# 5折交叉验证
cv = KFold(n_splits=5, shuffle=True, random_state=0)
results = cross_validate(
search, data, target, cv=cv,
return_estimator=True, n_jobs=2
)
# 输出结果
print(f"交叉验证 R² 分数: {results['test_score'].mean():.3f} ± {results['test_score'].std():.3f}")
# 查看各折的最佳参数
for i, estimator in enumerate(results["estimator"]):
print(f"折 {i+1}: {estimator.best_params_}, 树的数量: {estimator.best_estimator_.n_iter_}")
分类特征的支持
HistGradientBoostingRegressor 原生支持分类特征,无需手动编码。可以通过 categorical_features 参数指定哪些特征是分类特征:
import pandas as pd
from sklearn.ensemble import HistGradientBoostingRegressor
# 假设 DataFrame 中包含分类列
# categorical_features='from_dtype' 会自动识别 pandas 中的 category 类型
model = HistGradientBoostingRegressor(
categorical_features='from_dtype',
random_state=42
)
# 或手动指定分类特征的索引
model = HistGradientBoostingRegressor(
categorical_features=[0, 2, 5], # 第0、2、5列是分类特征
random_state=42
)
单调约束
在某些业务场景中,我们可能希望模型的预测结果与某个特征呈单调关系。例如,房价应该随着房屋面积的增加而单调递增:
# monotonic_cst: 1 表示单调递增,-1 表示单调递减,0 表示无约束
model = HistGradientBoostingRegressor(
monotonic_cst=[1, -1, 0], # 特征0递增,特征1递减,特征2无约束
random_state=42
)
缺失值处理
HistGradientBoostingRegressor 原生支持缺失值(NaN),无需手动填充。在训练过程中,树生长器会在每个分裂点学习缺失值样本应该分配到左子节点还是右子节点。如果某个特征在训练时没有遇到缺失值,则预测时缺失值会被映射到样本数最多的子节点。
常见调优建议
-
数据量较大时:设置
max_iter为一个较大的值(如 1000),配合early_stopping=True自动确定最优树的数量。 -
防止过拟合:
- 降低
learning_rate - 增加
l2_regularization - 减少
max_leaf_nodes或max_depth - 增加
min_samples_leaf
- 降低
-
小数据集:考虑降低
min_samples_leaf(默认 20 对几百个样本来说可能过大),或者考虑使用传统的GradientBoostingRegressor。 -
特征工程:虽然模型支持分类特征和缺失值,但合理的特征工程仍然能带来性能提升。
- 点赞
- 收藏
- 关注作者
评论(0)