Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
"""
|
|
|
|
|
===============================================
|
|
|
|
|
Feature transformations with ensembles of trees
|
|
|
|
|
===============================================
|
|
|
|
|
|
2021-02-02 04:24:22 +08:00
|
|
|
Transform your features into a higher dimensional, sparse space. Then train a
|
|
|
|
|
linear model on these features.
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
|
2021-02-02 04:24:22 +08:00
|
|
|
First fit an ensemble of trees (totally random trees, a random forest, or
|
|
|
|
|
gradient boosted trees) on the training set. Then each leaf of each tree in the
|
|
|
|
|
ensemble is assigned a fixed arbitrary feature index in a new feature space.
|
|
|
|
|
These leaf indices are then encoded in a one-hot fashion.
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
|
2021-02-02 04:24:22 +08:00
|
|
|
Each sample goes through the decisions of each tree of the ensemble and ends up
|
|
|
|
|
in one leaf per tree. The sample is encoded by setting feature values for these
|
|
|
|
|
leaves to 1 and the other feature values to 0.
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
|
|
|
|
|
The resulting transformer has then learned a supervised, sparse,
|
|
|
|
|
high-dimensional categorical embedding of the data.
|
2021-10-22 21:33:22 +08:00
|
|
|
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
"""
|
|
|
|
|
|
2021-10-22 21:33:22 +08:00
|
|
|
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
# Author: Tim Head <betatim@gmail.com>
|
|
|
|
|
#
|
|
|
|
|
# License: BSD 3 clause
|
|
|
|
|
|
2021-02-02 04:24:22 +08:00
|
|
|
# %%
|
|
|
|
|
# First, we will create a large dataset and split it into three sets:
|
|
|
|
|
#
|
|
|
|
|
# - a set to train the ensemble methods which are later used to as a feature
|
|
|
|
|
# engineering transformer;
|
|
|
|
|
# - a set to train the linear model;
|
|
|
|
|
# - a set to test the linear model.
|
|
|
|
|
#
|
|
|
|
|
# It is important to split the data in such way to avoid overfitting by leaking
|
|
|
|
|
# data.
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
|
|
|
|
|
from sklearn.datasets import make_classification
|
2015-09-11 02:26:39 +08:00
|
|
|
from sklearn.model_selection import train_test_split
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
X, y = make_classification(n_samples=80000, random_state=10)
|
|
|
|
|
|
|
|
|
|
X_full_train, X_test, y_full_train, y_test = train_test_split(
|
2021-09-03 23:19:46 +08:00
|
|
|
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
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# For each of the ensemble methods, we will use 10 estimators and a maximum
|
|
|
|
|
# depth of 3 levels.
|
|
|
|
|
|
|
|
|
|
n_estimators = 10
|
|
|
|
|
max_depth = 3
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# First, we will start by training the random forest and gradient boosting on
|
|
|
|
|
# the separated training set
|
|
|
|
|
|
|
|
|
|
from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier
|
|
|
|
|
|
|
|
|
|
random_forest = RandomForestClassifier(
|
2021-09-03 23:19:46 +08:00
|
|
|
n_estimators=n_estimators, max_depth=max_depth, random_state=10
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
random_forest.fit(X_train_ensemble, y_train_ensemble)
|
|
|
|
|
|
|
|
|
|
gradient_boosting = GradientBoostingClassifier(
|
2021-09-03 23:19:46 +08:00
|
|
|
n_estimators=n_estimators, max_depth=max_depth, random_state=10
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
_ = gradient_boosting.fit(X_train_ensemble, y_train_ensemble)
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# The :class:`~sklearn.ensemble.RandomTreesEmbedding` is an unsupervised method
|
|
|
|
|
# and thus does not required to be trained independently.
|
|
|
|
|
|
|
|
|
|
from sklearn.ensemble import RandomTreesEmbedding
|
|
|
|
|
|
|
|
|
|
random_tree_embedding = RandomTreesEmbedding(
|
2021-09-03 23:19:46 +08:00
|
|
|
n_estimators=n_estimators, max_depth=max_depth, random_state=0
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# Now, we will create three pipelines that will use the above embedding as
|
|
|
|
|
# a preprocessing stage.
|
|
|
|
|
#
|
|
|
|
|
# The random trees embedding can be directly pipelined with the logistic
|
|
|
|
|
# regression because it is a standard scikit-learn transformer.
|
|
|
|
|
|
|
|
|
|
from sklearn.linear_model import LogisticRegression
|
2015-10-16 23:56:38 +08:00
|
|
|
from sklearn.pipeline import make_pipeline
|
Example to demonstrate use of tree.apply() method
This example trains several tree based ensemble methods and uses
them to transform the data into a high dimensional, sparse space.
The trains a linear model on this new feature space. The idea is
taken from:
Practical Lessons from Predicting Clicks on Ads at Facebook Junfeng Pan,
He Xinran, Ou Jin, Tianbing XU, Bo Liu, Tao Xu, Yanxin Shi, Antoine
Atallah, Ralf Herbrich, Stuart Bowers, Joaquin Quiñonero Candela
International Workshop on Data Mining for Online Advertising (ADKDD)
https://www.facebook.com/publications/329190253909587/
2015-07-27 22:38:50 +08:00
|
|
|
|
2021-09-03 23:19:46 +08:00
|
|
|
rt_model = make_pipeline(random_tree_embedding, LogisticRegression(max_iter=1000))
|
2021-02-02 04:24:22 +08:00
|
|
|
rt_model.fit(X_train_linear, y_train_linear)
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# Then, we can pipeline random forest or gradient boosting with a logistic
|
|
|
|
|
# regression. However, the feature transformation will happen by calling the
|
|
|
|
|
# method `apply`. The pipeline in scikit-learn expects a call to `transform`.
|
|
|
|
|
# Therefore, we wrapped the call to `apply` within a `FunctionTransformer`.
|
|
|
|
|
|
|
|
|
|
from sklearn.preprocessing import FunctionTransformer
|
|
|
|
|
from sklearn.preprocessing import OneHotEncoder
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def rf_apply(X, model):
|
|
|
|
|
return model.apply(X)
|
|
|
|
|
|
|
|
|
|
|
2021-09-03 23:19:46 +08:00
|
|
|
rf_leaves_yielder = FunctionTransformer(rf_apply, kw_args={"model": random_forest})
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
rf_model = make_pipeline(
|
2021-09-03 23:19:46 +08:00
|
|
|
rf_leaves_yielder,
|
|
|
|
|
OneHotEncoder(handle_unknown="ignore"),
|
|
|
|
|
LogisticRegression(max_iter=1000),
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
rf_model.fit(X_train_linear, y_train_linear)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
def gbdt_apply(X, model):
|
|
|
|
|
return model.apply(X)[:, :, 0]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
gbdt_leaves_yielder = FunctionTransformer(
|
2021-09-03 23:19:46 +08:00
|
|
|
gbdt_apply, kw_args={"model": gradient_boosting}
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
gbdt_model = make_pipeline(
|
2021-09-03 23:19:46 +08:00
|
|
|
gbdt_leaves_yielder,
|
|
|
|
|
OneHotEncoder(handle_unknown="ignore"),
|
|
|
|
|
LogisticRegression(max_iter=1000),
|
|
|
|
|
)
|
2021-02-02 04:24:22 +08:00
|
|
|
gbdt_model.fit(X_train_linear, y_train_linear)
|
|
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
# We can finally show the different ROC curves for all the models.
|
|
|
|
|
|
|
|
|
|
import matplotlib.pyplot as plt
|
2021-09-03 23:19:46 +08:00
|
|
|
from sklearn.metrics import RocCurveDisplay
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
fig, 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:
|
2021-09-03 23:19:46 +08:00
|
|
|
model_displays[name] = RocCurveDisplay.from_estimator(
|
|
|
|
|
pipeline, X_test, y_test, ax=ax, name=name
|
|
|
|
|
)
|
|
|
|
|
_ = ax.set_title("ROC curve")
|
2021-02-02 04:24:22 +08:00
|
|
|
|
|
|
|
|
# %%
|
|
|
|
|
fig, 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)
|
2021-09-03 23:19:46 +08:00
|
|
|
_ = ax.set_title("ROC curve (zoomed in at top left)")
|