注意
跳转至页面底部 下载完整示例代码,或通过 JupyterLite 或 Binder 在浏览器中运行此示例。
使用树集成进行特征转换#
将您的特征转换为高维稀疏空间,然后在此类特征上训练线性模型。
首先在训练集上拟合一个树集成(完全随机树、随机森林或梯度提升树)。随后,集成中每棵树的每个叶子节点都被分配到一个新特征空间中固定的任意特征索引。这些叶子索引随后以独热(one-hot)方式进行编码。
每个样本都会穿过集成中每棵树的决策路径,并最终停在每棵树的一个叶子节点上。通过将这些叶子对应的特征值设为 1,其余设为 0,从而对样本进行编码。
由此得到的转换器便学习到了数据的监督式、稀疏、高维类别嵌入。
# Authors: The scikit-learn developers
# SPDX-License-Identifier: BSD-3-Clause
首先,我们将创建一个大型数据集并将其拆分为三个部分:
一个用于训练集成方法的集合,该集合稍后将作为特征工程转换器使用;
一个用于训练线性模型的集合;
一个用于测试线性模型的集合。
以这种方式拆分数据非常重要,可以避免因数据泄露导致的过拟合。
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
X, y = make_classification(n_samples=80_000, random_state=10)
X_full_train, X_test, y_full_train, y_test = train_test_split(
X, y, test_size=0.5, random_state=10
)
X_train_ensemble, X_train_linear, y_train_ensemble, y_train_linear = train_test_split(
X_full_train, y_full_train, test_size=0.5, random_state=10
)
对于每种集成方法,我们将使用 10 个估计器(estimators)和 3 层的最大深度。
n_estimators = 10
max_depth = 3
首先,我们将在分离出的训练集上开始训练随机森林和梯度提升模型。
from sklearn.ensemble import GradientBoostingClassifier, RandomForestClassifier
random_forest = RandomForestClassifier(
n_estimators=n_estimators, max_depth=max_depth, random_state=10
)
random_forest.fit(X_train_ensemble, y_train_ensemble)
gradient_boosting = GradientBoostingClassifier(
n_estimators=n_estimators, max_depth=max_depth, random_state=10
)
_ = gradient_boosting.fit(X_train_ensemble, y_train_ensemble)
请注意,对于中等规模数据集(n_samples >= 10_000),HistGradientBoostingClassifier 的速度要快得多,尽管这并非本示例的情况。
RandomTreesEmbedding 是一种无监督方法,因此不需要单独训练。
from sklearn.ensemble import RandomTreesEmbedding
random_tree_embedding = RandomTreesEmbedding(
n_estimators=n_estimators, max_depth=max_depth, random_state=0
)
现在,我们将创建三个流水线(pipelines),它们将使用上述嵌入作为预处理阶段。
由于随机树嵌入是一个标准的 scikit-learn 转换器,它可以直接与逻辑回归流水线化。
from sklearn.linear_model import LogisticRegression
from sklearn.pipeline import make_pipeline
rt_model = make_pipeline(random_tree_embedding, LogisticRegression(max_iter=1000))
rt_model.fit(X_train_linear, y_train_linear)
Pipeline(steps=[('randomtreesembedding',
RandomTreesEmbedding(max_depth=3, n_estimators=10,
random_state=0)),
('logisticregression', LogisticRegression(max_iter=1000))])在 Jupyter 环境中,请重新运行此单元格以显示 HTML 表示形式或信任 notebook。在 GitHub 上,HTML 表示形式无法渲染,请尝试使用 nbviewer.org 加载此页面。
参数
拟合属性
参数
拟合属性
75 个特征
| randomtreesembedding_0_3 |
| randomtreesembedding_0_4 |
| randomtreesembedding_0_6 |
| randomtreesembedding_0_7 |
| randomtreesembedding_0_10 |
| randomtreesembedding_0_11 |
| randomtreesembedding_0_13 |
| randomtreesembedding_0_14 |
| randomtreesembedding_1_3 |
| randomtreesembedding_1_4 |
| randomtreesembedding_1_6 |
| randomtreesembedding_1_7 |
| randomtreesembedding_1_10 |
| randomtreesembedding_1_11 |
| randomtreesembedding_1_13 |
| randomtreesembedding_1_14 |
| randomtreesembedding_2_3 |
| randomtreesembedding_2_4 |
| randomtreesembedding_2_6 |
| randomtreesembedding_2_7 |
| randomtreesembedding_2_10 |
| randomtreesembedding_2_11 |
| randomtreesembedding_2_13 |
| randomtreesembedding_2_14 |
| randomtreesembedding_3_3 |
| randomtreesembedding_3_4 |
| randomtreesembedding_3_6 |
| randomtreesembedding_3_7 |
| randomtreesembedding_3_10 |
| randomtreesembedding_3_11 |
| randomtreesembedding_3_13 |
| randomtreesembedding_3_14 |
| randomtreesembedding_4_3 |
| randomtreesembedding_4_4 |
| randomtreesembedding_4_6 |
| randomtreesembedding_4_7 |
| randomtreesembedding_4_10 |
| randomtreesembedding_4_11 |
| randomtreesembedding_4_13 |
| randomtreesembedding_4_14 |
| randomtreesembedding_5_3 |
| randomtreesembedding_5_4 |
| randomtreesembedding_5_6 |
| randomtreesembedding_5_7 |
| randomtreesembedding_5_10 |
| randomtreesembedding_5_11 |
| randomtreesembedding_5_12 |
| randomtreesembedding_6_3 |
| randomtreesembedding_6_4 |
| randomtreesembedding_6_6 |
| randomtreesembedding_6_7 |
| randomtreesembedding_6_9 |
| randomtreesembedding_6_11 |
| randomtreesembedding_6_12 |
| randomtreesembedding_7_3 |
| randomtreesembedding_7_4 |
| randomtreesembedding_7_6 |
| randomtreesembedding_7_7 |
| randomtreesembedding_7_10 |
| randomtreesembedding_7_11 |
| randomtreesembedding_7_13 |
| randomtreesembedding_7_14 |
| randomtreesembedding_8_1 |
| randomtreesembedding_8_4 |
| randomtreesembedding_8_5 |
| randomtreesembedding_8_7 |
| randomtreesembedding_8_8 |
| randomtreesembedding_9_3 |
| randomtreesembedding_9_4 |
| randomtreesembedding_9_6 |
| randomtreesembedding_9_7 |
| randomtreesembedding_9_10 |
| randomtreesembedding_9_11 |
| randomtreesembedding_9_13 |
| randomtreesembedding_9_14 |
参数
拟合属性
最后,我们可以将随机森林或梯度提升与逻辑回归进行流水线化。然而,特征转换是通过调用 apply 方法实现的。scikit-learn 中的流水线期望调用 transform。因此,我们用 FunctionTransformer 包装了对 apply 的调用。
from sklearn.preprocessing import FunctionTransformer, OneHotEncoder
def rf_apply(X, model):
return model.apply(X)
rf_leaves_yielder = FunctionTransformer(rf_apply, kw_args={"model": random_forest})
rf_model = make_pipeline(
rf_leaves_yielder,
OneHotEncoder(handle_unknown="ignore"),
LogisticRegression(max_iter=1000),
)
rf_model.fit(X_train_linear, y_train_linear)
Pipeline(steps=[('functiontransformer',
FunctionTransformer(func=<function rf_apply at 0x78414c6c97a0>,
kw_args={'model': RandomForestClassifier(max_depth=3,
n_estimators=10,
random_state=10)})),
('onehotencoder', OneHotEncoder(handle_unknown='ignore')),
('logisticregression', LogisticRegression(max_iter=1000))])在 Jupyter 环境中,请重新运行此单元格以显示 HTML 表示形式或信任 notebook。在 GitHub 上,HTML 表示形式无法渲染,请尝试使用 nbviewer.org 加载此页面。
参数
拟合属性
参数
拟合属性
| 名称 | 类型 | 值 |
|---|---|---|
|
n_features_in_ n_features_in_: int 在 :term:`fit` 期间看到的特征数量。 .. 新增版本:: 0.24 |
int | 20 |
参数
拟合属性
| 名称 | 类型 | 值 |
|---|---|---|
|
categories_ categories_: 数组列表 在拟合期间确定的每个特征的类别(按 X 中特征的顺序,且与 ``transform`` 的输出相对应)。这包括在 ``drop`` 中指定的类别(如果有)。 |
list | [array([ 3, 4..., 11, 13, 14]), array([ 3, 4..., 11, 13, 14]), array([ 3, 4..., 11, 13, 14]), array([ 3, 4..., 11, 13, 14]), ...] |
|
drop_idx_ drop_idx_: 形状为 (n_features,) 的数组 - ``drop_idx_[i]`` 是 ``categories_[i]`` 中要为每个特征删除的类别的索引。 - 如果索引为 ``i`` 的特征不需要删除任何类别,则 ``drop_idx_[i] = None``,例如当 `drop='if_binary'` 且该特征不是二元特征时。 - 如果将保留所有转换后的特征,则 ``drop_idx_ = None``。 如果通过将 `min_frequency` 或 `max_categories` 设置为非默认值启用了罕见类别,且 `drop_idx[i]` 对应于一个罕见类别,则整个罕见类别将被删除。 .. 版本变更:: 0.23 增加了包含 `None` 值的可能性。 |
NoneType | None |
|
n_features_in_ n_features_in_: int 在 :term:`fit` 期间看到的特征数量。 .. 新增版本:: 1.0 |
int | 10 |
79 个特征
| x0_3 |
| x0_4 |
| x0_6 |
| x0_7 |
| x0_10 |
| x0_11 |
| x0_13 |
| x0_14 |
| x1_3 |
| x1_4 |
| x1_6 |
| x1_7 |
| x1_10 |
| x1_11 |
| x1_13 |
| x1_14 |
| x2_3 |
| x2_4 |
| x2_6 |
| x2_7 |
| x2_10 |
| x2_11 |
| x2_13 |
| x2_14 |
| x3_3 |
| x3_4 |
| x3_6 |
| x3_7 |
| x3_10 |
| x3_11 |
| x3_13 |
| x3_14 |
| x4_3 |
| x4_4 |
| x4_6 |
| x4_7 |
| x4_10 |
| x4_11 |
| x4_13 |
| x4_14 |
| x5_3 |
| x5_4 |
| x5_6 |
| x5_7 |
| x5_10 |
| x5_11 |
| x5_13 |
| x5_14 |
| x6_3 |
| x6_4 |
| x6_6 |
| x6_7 |
| x6_10 |
| x6_11 |
| x6_13 |
| x6_14 |
| x7_3 |
| x7_4 |
| x7_6 |
| x7_7 |
| x7_10 |
| x7_11 |
| x7_13 |
| x7_14 |
| x8_3 |
| x8_4 |
| x8_6 |
| x8_7 |
| x8_10 |
| x8_11 |
| x8_13 |
| x8_14 |
| x9_3 |
| x9_4 |
| x9_7 |
| x9_10 |
| x9_11 |
| x9_13 |
| x9_14 |
参数
拟合属性
def gbdt_apply(X, model):
return model.apply(X)[:, :, 0]
gbdt_leaves_yielder = FunctionTransformer(
gbdt_apply, kw_args={"model": gradient_boosting}
)
gbdt_model = make_pipeline(
gbdt_leaves_yielder,
OneHotEncoder(handle_unknown="ignore"),
LogisticRegression(max_iter=1000),
)
gbdt_model.fit(X_train_linear, y_train_linear)
Pipeline(steps=[('functiontransformer',
FunctionTransformer(func=<function gbdt_apply at 0x78414c6c9e80>,
kw_args={'model': GradientBoostingClassifier(n_estimators=10,
random_state=10)})),
('onehotencoder', OneHotEncoder(handle_unknown='ignore')),
('logisticregression', LogisticRegression(max_iter=1000))])在 Jupyter 环境中,请重新运行此单元格以显示 HTML 表示形式或信任 notebook。在 GitHub 上,HTML 表示形式无法渲染,请尝试使用 nbviewer.org 加载此页面。
参数
拟合属性
参数
拟合属性
| 名称 | 类型 | 值 |
|---|---|---|
|
n_features_in_ n_features_in_: int 在 :term:`fit` 期间看到的特征数量。 .. 新增版本:: 0.24 |
int | 20 |
参数
拟合属性
| 名称 | 类型 | 值 |
|---|---|---|
|
categories_ categories_: 数组列表 在拟合期间确定的每个特征的类别(按 X 中特征的顺序,且与 ``transform`` 的输出相对应)。这包括在 ``drop`` 中指定的类别(如果有)。 |
list | [array([ 4., ...1., 13., 14.]), array([ 4., ...1., 13., 14.]), array([ 4., ...1., 13., 14.]), array([ 4., ...1., 13., 14.]), ...] |
|
drop_idx_ drop_idx_: 形状为 (n_features,) 的数组 - ``drop_idx_[i]`` 是 ``categories_[i]`` 中要为每个特征删除的类别的索引。 - 如果索引为 ``i`` 的特征不需要删除任何类别,则 ``drop_idx_[i] = None``,例如当 `drop='if_binary'` 且该特征不是二元特征时。 - 如果将保留所有转换后的特征,则 ``drop_idx_ = None``。 如果通过将 `min_frequency` 或 `max_categories` 设置为非默认值启用了罕见类别,且 `drop_idx[i]` 对应于一个罕见类别,则整个罕见类别将被删除。 .. 版本变更:: 0.23 增加了包含 `None` 值的可能性。 |
NoneType | None |
|
n_features_in_ n_features_in_: int 在 :term:`fit` 期间看到的特征数量。 .. 新增版本:: 1.0 |
int | 10 |
76 个特征
| x0_4.0 |
| x0_6.0 |
| x0_7.0 |
| x0_10.0 |
| x0_11.0 |
| x0_13.0 |
| x0_14.0 |
| x1_4.0 |
| x1_6.0 |
| x1_7.0 |
| x1_10.0 |
| x1_11.0 |
| x1_13.0 |
| x1_14.0 |
| x2_4.0 |
| x2_6.0 |
| x2_7.0 |
| x2_10.0 |
| x2_11.0 |
| x2_13.0 |
| x2_14.0 |
| x3_4.0 |
| x3_6.0 |
| x3_7.0 |
| x3_10.0 |
| x3_11.0 |
| x3_13.0 |
| x3_14.0 |
| x4_3.0 |
| x4_4.0 |
| x4_6.0 |
| x4_7.0 |
| x4_10.0 |
| x4_11.0 |
| x4_13.0 |
| x4_14.0 |
| x5_3.0 |
| x5_4.0 |
| x5_6.0 |
| x5_7.0 |
| x5_10.0 |
| x5_11.0 |
| x5_13.0 |
| x5_14.0 |
| x6_3.0 |
| x6_4.0 |
| x6_6.0 |
| x6_7.0 |
| x6_10.0 |
| x6_11.0 |
| x6_13.0 |
| x6_14.0 |
| x7_3.0 |
| x7_4.0 |
| x7_6.0 |
| x7_7.0 |
| x7_10.0 |
| x7_11.0 |
| x7_13.0 |
| x7_14.0 |
| x8_3.0 |
| x8_4.0 |
| x8_6.0 |
| x8_7.0 |
| x8_10.0 |
| x8_11.0 |
| x8_13.0 |
| x8_14.0 |
| x9_3.0 |
| x9_4.0 |
| x9_6.0 |
| x9_7.0 |
| x9_10.0 |
| x9_11.0 |
| x9_13.0 |
| x9_14.0 |
参数
拟合属性
最后,我们可以展示所有模型不同的 ROC 曲线。
import matplotlib.pyplot as plt
from sklearn.metrics import RocCurveDisplay
_, ax = plt.subplots()
models = [
("RT embedding -> LR", rt_model),
("RF", random_forest),
("RF embedding -> LR", rf_model),
("GBDT", gradient_boosting),
("GBDT embedding -> LR", gbdt_model),
]
model_displays = {}
for name, pipeline in models:
model_displays[name] = RocCurveDisplay.from_estimator(
pipeline, X_test, y_test, ax=ax, name=name
)
_ = ax.set_title("ROC curve")

_, ax = plt.subplots()
for name, pipeline in models:
model_displays[name].plot(ax=ax)
ax.set_xlim(0, 0.2)
ax.set_ylim(0.8, 1)
_ = ax.set_title("ROC curve (zoomed in at top left)")

脚本总运行时间: (0 分 2.366 秒)
相关示例