2019-01-05 12:22:36 +08:00
|
|
|
r"""
|
2013-01-15 17:30:31 +08:00
|
|
|
=====================================
|
2013-01-15 18:33:52 +08:00
|
|
|
Multi-class AdaBoosted Decision Trees
|
2013-01-15 17:30:31 +08:00
|
|
|
=====================================
|
|
|
|
|
|
2017-07-30 13:22:10 +08:00
|
|
|
This example reproduces Figure 1 of Zhu et al [1]_ and shows how boosting can
|
2013-01-15 17:30:31 +08:00
|
|
|
improve prediction accuracy on a multi-class problem. The classification
|
|
|
|
|
dataset is constructed by taking a ten-dimensional standard normal distribution
|
|
|
|
|
and defining three classes separated by nested concentric ten-dimensional
|
|
|
|
|
spheres such that roughly equal numbers of samples are in each class (quantiles
|
2013-01-30 09:15:24 +08:00
|
|
|
of the :math:`\chi^2` distribution).
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2017-07-30 13:22:10 +08:00
|
|
|
The performance of the SAMME and SAMME.R [1]_ algorithms are compared. SAMME.R
|
2013-02-04 01:45:33 +08:00
|
|
|
uses the probability estimates to update the additive model, while SAMME uses
|
|
|
|
|
the classifications only. As the example illustrates, the SAMME.R algorithm
|
|
|
|
|
typically converges faster than SAMME, achieving a lower test error with fewer
|
|
|
|
|
boosting iterations. The error of each algorithm on the test set after each
|
|
|
|
|
boosting iteration is shown on the left, the classification error on the test
|
|
|
|
|
set of each tree is shown in the middle, and the boost weight of each tree is
|
|
|
|
|
shown on the right. All trees have a weight of one in the SAMME.R algorithm and
|
|
|
|
|
therefore are not shown.
|
2013-01-15 17:30:31 +08:00
|
|
|
|
|
|
|
|
.. [1] J. Zhu, H. Zou, S. Rosset, T. Hastie, "Multi-class AdaBoost", 2009.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
|
2013-01-15 17:32:23 +08:00
|
|
|
# Author: Noel Dawe <noel.dawe@gmail.com>
|
|
|
|
|
#
|
2013-04-30 14:23:46 +08:00
|
|
|
# License: BSD 3 clause
|
2013-01-15 17:32:23 +08:00
|
|
|
|
2014-02-27 17:22:21 +08:00
|
|
|
import matplotlib.pyplot as plt
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2013-01-30 08:59:18 +08:00
|
|
|
from sklearn.datasets import make_gaussian_quantiles
|
2013-02-14 09:05:35 +08:00
|
|
|
from sklearn.ensemble import AdaBoostClassifier
|
2013-01-15 17:30:31 +08:00
|
|
|
from sklearn.metrics import accuracy_score
|
2013-02-14 09:05:35 +08:00
|
|
|
from sklearn.tree import DecisionTreeClassifier
|
2013-01-15 17:30:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
X, y = make_gaussian_quantiles(
|
|
|
|
|
n_samples=13000, n_features=10, n_classes=3, random_state=1
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
n_split = 3000
|
|
|
|
|
|
|
|
|
|
X_train, X_test = X[:n_split], X[n_split:]
|
|
|
|
|
y_train, y_test = y[:n_split], y[n_split:]
|
|
|
|
|
|
|
|
|
|
bdt_real = AdaBoostClassifier(
|
2021-11-17 01:16:58 +08:00
|
|
|
DecisionTreeClassifier(max_depth=2), n_estimators=300, learning_rate=1
|
2013-01-15 17:30:31 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
bdt_discrete = AdaBoostClassifier(
|
|
|
|
|
DecisionTreeClassifier(max_depth=2),
|
2021-11-17 01:16:58 +08:00
|
|
|
n_estimators=300,
|
2013-01-15 17:30:31 +08:00
|
|
|
learning_rate=1.5,
|
2013-01-23 15:53:49 +08:00
|
|
|
algorithm="SAMME",
|
|
|
|
|
)
|
2013-01-15 17:30:31 +08:00
|
|
|
|
|
|
|
|
bdt_real.fit(X_train, y_train)
|
|
|
|
|
bdt_discrete.fit(X_train, y_train)
|
|
|
|
|
|
|
|
|
|
real_test_errors = []
|
|
|
|
|
discrete_test_errors = []
|
|
|
|
|
|
2013-03-19 08:39:47 +08:00
|
|
|
for real_test_predict, discrete_train_predict in zip(
|
2013-01-15 17:30:31 +08:00
|
|
|
bdt_real.staged_predict(X_test), bdt_discrete.staged_predict(X_test)
|
|
|
|
|
):
|
2013-01-15 18:40:47 +08:00
|
|
|
real_test_errors.append(1.0 - accuracy_score(real_test_predict, y_test))
|
|
|
|
|
discrete_test_errors.append(1.0 - accuracy_score(discrete_train_predict, y_test))
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2014-04-17 08:20:53 +08:00
|
|
|
n_trees_discrete = len(bdt_discrete)
|
|
|
|
|
n_trees_real = len(bdt_real)
|
|
|
|
|
|
|
|
|
|
# Boosting might terminate early, but the following arrays are always
|
|
|
|
|
# n_estimators long. We crop them to the actual number of trees here:
|
|
|
|
|
discrete_estimator_errors = bdt_discrete.estimator_errors_[:n_trees_discrete]
|
|
|
|
|
real_estimator_errors = bdt_real.estimator_errors_[:n_trees_real]
|
|
|
|
|
discrete_estimator_weights = bdt_discrete.estimator_weights_[:n_trees_discrete]
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.figure(figsize=(15, 5))
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.subplot(131)
|
2014-04-17 14:40:56 +08:00
|
|
|
plt.plot(range(1, n_trees_discrete + 1), discrete_test_errors, c="black", label="SAMME")
|
|
|
|
|
plt.plot(
|
|
|
|
|
range(1, n_trees_real + 1),
|
2014-04-17 08:20:53 +08:00
|
|
|
real_test_errors,
|
|
|
|
|
c="black",
|
|
|
|
|
linestyle="dashed",
|
|
|
|
|
label="SAMME.R",
|
|
|
|
|
)
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.legend()
|
|
|
|
|
plt.ylim(0.18, 0.62)
|
|
|
|
|
plt.ylabel("Test Error")
|
|
|
|
|
plt.xlabel("Number of Trees")
|
|
|
|
|
|
|
|
|
|
plt.subplot(132)
|
2014-04-17 14:40:56 +08:00
|
|
|
plt.plot(
|
|
|
|
|
range(1, n_trees_discrete + 1),
|
|
|
|
|
discrete_estimator_errors,
|
2014-04-17 08:20:53 +08:00
|
|
|
"b",
|
|
|
|
|
label="SAMME",
|
|
|
|
|
alpha=0.5,
|
|
|
|
|
)
|
2014-04-17 14:40:56 +08:00
|
|
|
plt.plot(
|
|
|
|
|
range(1, n_trees_real + 1), real_estimator_errors, "r", label="SAMME.R", alpha=0.5
|
2014-04-17 08:20:53 +08:00
|
|
|
)
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.legend()
|
|
|
|
|
plt.ylabel("Error")
|
|
|
|
|
plt.xlabel("Number of Trees")
|
2014-04-17 08:20:53 +08:00
|
|
|
plt.ylim((0.2, max(real_estimator_errors.max(), discrete_estimator_errors.max()) * 1.2))
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.xlim((-20, len(bdt_discrete) + 20))
|
2013-01-15 17:30:31 +08:00
|
|
|
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.subplot(133)
|
2014-04-17 14:40:56 +08:00
|
|
|
plt.plot(range(1, n_trees_discrete + 1), discrete_estimator_weights, "b", label="SAMME")
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.legend()
|
|
|
|
|
plt.ylabel("Weight")
|
|
|
|
|
plt.xlabel("Number of Trees")
|
2014-04-17 08:20:53 +08:00
|
|
|
plt.ylim((0, discrete_estimator_weights.max() * 1.2))
|
|
|
|
|
plt.xlim((-20, n_trees_discrete + 20))
|
2013-01-15 17:30:31 +08:00
|
|
|
|
|
|
|
|
# prevent overlapping y-axis labels
|
2014-02-27 17:22:21 +08:00
|
|
|
plt.subplots_adjust(wspace=0.25)
|
|
|
|
|
plt.show()
|