使用树的集成进行特征转换#

将您的特征转换为更高维的稀疏空间。然后,根据这些特征训练线性模型。

首先,在训练集上拟合树的集成(完全随机树、随机森林或梯度提升树)。然后,将集成中每棵树的每个叶节点分配给新特征空间中的固定任意特征索引。然后,以独热编码的方式对这些叶节点索引进行编码。

每个样本都会经过集成中每棵树的决策,并最终落入每棵树的一个叶节点中。通过将这些叶节点的特征值设置为 1,并将其他特征值设置为 0 来对样本进行编码。

然后,生成的转换器学习了数据的监督、稀疏、高维分类嵌入。

# Author: Tim Head <[email protected]>
#
# License: 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 个估计器和最大 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)

请注意,HistGradientBoostingClassifierGradientBoostingClassifier 快得多,从中等数据集 (n_samples >= 10_000) 开始,本例并非如此。

RandomTreesEmbedding 是一种无监督方法,因此不需要独立训练。

from sklearn.ensemble import RandomTreesEmbedding

random_tree_embedding = RandomTreesEmbedding(
    n_estimators=n_estimators, max_depth=max_depth, random_state=0
)

现在,我们将创建三个管道,它们将使用上述嵌入作为预处理阶段。

随机树嵌入可以直接与逻辑回归一起流水线化,因为它是一个标准的 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 表示形式或信任笔记本。
在 GitHub 上,HTML 表示形式无法呈现,请尝试使用 nbviewer.org 加载此页面。


然后,我们可以将随机森林或梯度提升与逻辑回归一起流水线化。但是,特征转换将通过调用 apply 方法来完成。scikit-learn 中的管道需要调用 transform。因此,我们将对 apply 的调用包装在 FunctionTransformer 中。

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 0x7f4dfdebfca0>,
                                     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 表示形式或信任笔记本。
在 GitHub 上,HTML 表示形式无法呈现,请尝试使用 nbviewer.org 加载此页面。


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 0x7f4dfc1fab80>,
                                     kw_args={'model': GradientBoostingClassifier(n_estimators=10,
                                                                                  random_state=10)})),
                ('onehotencoder', OneHotEncoder(handle_unknown='ignore')),
                ('logisticregression', LogisticRegression(max_iter=1000))])
在 Jupyter 环境中,请重新运行此单元格以显示 HTML 表示形式或信任笔记本。
在 GitHub 上,HTML 表示形式无法呈现,请尝试使用 nbviewer.org 加载此页面。


我们最终可以显示所有模型的不同 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")
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)")
ROC curve (zoomed in at top left)

脚本总运行时间:(0 分钟 2.772 秒)

相关示例

手写数字的流形学习:局部线性嵌入、等距映射…

手写数字的流形学习:局部线性嵌入、等距映射...

scikit-learn 0.22 版本亮点

scikit-learn 0.22 版本亮点

比较随机森林和直方图梯度提升模型

比较随机森林和直方图梯度提升模型

使用可视化 API 绘制 ROC 曲线

使用可视化 API 绘制 ROC 曲线

由 Sphinx-Gallery 生成的图库