单调约束对梯度提升树的影响

机器学习领域,梯度提升树是一种流行的集成学习方法,它通过构建多个决策树来提高模型的预测性能。然而,在某些情况下,希望模型能够遵循特定的趋势,例如,与某个特征正相关或负相关。这时,可以在训练过程中对特征施加单调性约束,以引导模型学习到期望的趋势。

为了展示单调约束的效果,构建了一个人工数据集。在这个数据集中,目标值与第一个特征总体上呈正相关,而与第二个特征总体上呈负相关。这种相关性中包含了一些随机和非随机的变化。通过在训练过程中对特征施加单调性增加或减少的约束,模型能够更好地遵循总体趋势,而不是受到这些变化的影响。

下面是一个使用Python中的scikit-learn库来实现这一过程的示例代码。首先,导入必要的库,并设置随机数生成器的种子,以确保结果的可重复性。然后,生成了两个特征的数据,并添加了一些噪声。目标值与第一个特征正相关,与第二个特征负相关,但这种关系中包含了一些正弦和余弦函数的波动。

import matplotlib.pyplot as plt import numpy as np from sklearn.ensemble import HistGradientBoostingRegressor from sklearn.inspection import PartialDependenceDisplay # 设置随机数生成器的种子 rng = np.random.RandomState(0) n_samples = 1000 f_0 = rng.rand(n_samples) f_1 = rng.rand(n_samples) X = np.c_[f_0, f_1] noise = rng.normal(loc=0.0, scale=0.01, size=n_samples) # 目标值与第一个特征正相关,与第二个特征负相关 y = 5 * f_0 + np.sin(10 * np.pi * f_0) - 5 * f_1 - np.cos(10 * np.pi * f_1) + noise

接下来,首先在没有任何约束的情况下对这个数据集进行建模。然后,对同一个数据集施加单调性增加和减少的约束,并再次进行建模。通过比较两个模型的部分依赖图,可以观察到,没有约束的模型捕捉到了数据的波动,而有约束的模型则遵循了总体趋势,忽略了局部变化。

# 无约束模型 gbdt_no_cst = HistGradientBoostingRegressor() gbdt_no_cst.fit(X, y) # 有单调性约束的模型 gbdt_with_monotonic_cst = HistGradientBoostingRegressor(monotonic_cst=[1, -1]) gbdt_with_monotonic_cst.fit(X, y) # 显示两个模型的部分依赖图 fig, ax = plt.subplots() disp = PartialDependenceDisplay.from_estimator(gbdt_no_cst, X, features=[0, 1], feature_names=("第一特征", "第二特征"), line_kw={"linewidth": 4, "label": "无约束", "color": "tab:blue"}, ax=ax) PartialDependenceDisplay.from_estimator(gbdt_with_monotonic_cst, X, features=[0, 1], line_kw={"linewidth": 4, "label": "有约束", "color": "tab:orange"}, ax=disp.axes_) for f_idx in (0, 1): disp.axes_[0, f_idx].plot(X[:, f_idx], y, "o", alpha=0.3, zorder=-1, color="tab:green") disp.axes_[0, f_idx].set_ylim(-6, 6) plt.legend() fig.suptitle("单调约束对部分依赖的影响") plt.show()

通过上述代码,可以看到,单调约束有效地引导了模型的学习过程,使其能够更好地捕捉数据的总体趋势。此外,如果训练数据中包含了特征名称,还可以通过传递一个字典来指定单调约束,这为模型训练提供了更多的灵活性。

import pandas as pd # 将特征数据转换为DataFrame,并指定特征名称 X_df = pd.DataFrame(X, columns=["f_0", "f_1"]) # 使用特征名称指定单调约束 gbdt_with_monotonic_cst_df = HistGradientBoostingRegressor(monotonic_cst={"f_0": 1, "f_1": -1}) gbdt_with_monotonic_cst_df.fit(X_df, y) # 验证两个模型的预测结果是否一致 np.allclose(gbdt_with_monotonic_cst_df.predict(X_df), gbdt_with_monotonic_cst.predict(X))
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485