2011-04-02 05:28:20 +08:00
|
|
|
"""
|
|
|
|
|
=================================================
|
|
|
|
|
Plot multi-class DecisionTree on the iris dataset
|
|
|
|
|
=================================================
|
|
|
|
|
|
2011-09-26 01:59:22 +08:00
|
|
|
Plot decision surface of multi-class :ref:`decision tree <tree>` on iris
|
|
|
|
|
dataset on pairwise selection of features.
|
2011-09-26 01:30:23 +08:00
|
|
|
|
2011-09-26 01:59:22 +08:00
|
|
|
For each pair of iris features, the decision tree learn decision
|
|
|
|
|
boundaries made of combination of simple thresholding rules on the train
|
|
|
|
|
observations.
|
2011-04-02 05:28:20 +08:00
|
|
|
"""
|
|
|
|
|
print __doc__
|
|
|
|
|
|
|
|
|
|
import numpy as np
|
|
|
|
|
import pylab as pl
|
2011-09-04 02:58:20 +08:00
|
|
|
from sklearn import datasets
|
|
|
|
|
from sklearn.tree import DecisionTreeClassifier
|
2011-04-02 05:28:20 +08:00
|
|
|
|
|
|
|
|
# import some data to play with
|
|
|
|
|
iris = datasets.load_iris()
|
2011-09-26 01:30:23 +08:00
|
|
|
for pairidx, pair in enumerate([[0, 1], [0, 2], [0, 3],
|
|
|
|
|
[1, 2], [1, 3], [2, 3]]):
|
|
|
|
|
X = iris.data[:, pair] # we only take the two corresponding features
|
2011-04-02 05:28:20 +08:00
|
|
|
y = iris.target
|
Refactored decision trees and forests to support CART algorithm.
Notable changes:
1) Supports classification and regression
2) 3 classification criteria, 1 regression criterion
3) A new dataset is provided to test regression (Boston House Prices)
4) Weights are removed from the algorithm entirely. If the need for weights can be justified, I would welcome reintroducing them, but for the refactoring I left them out.
5) The subset of dimensions (F) to split on is fixed for the entire tree, not at each node. This is more in line with CART and RandomForests.
6) A max_depth parameter is offered to limit the size of the constructed trees.
7) Randomisation is fixed with python's random module, but can be seeded.
8) For classification, the number of classes must be provided when the tree is constructed. This is because the tree cannot necessarily infer the correct number of labels at the time of training if only a subset of the data is used for individual trees.
9) For classification, labels are not normalised internally. Labels must be provided to the algorithm in the range [0, ..., K)
10) For classification, the leaf nodes retain the distribution of classes. This means that it is possible to query the tree for the probability distribution of a test sample
2011-07-29 19:37:53 +08:00
|
|
|
K=3
|
2011-04-02 05:28:20 +08:00
|
|
|
colors = "bry"
|
|
|
|
|
|
|
|
|
|
# shuffle
|
|
|
|
|
idx = np.arange(X.shape[0])
|
|
|
|
|
np.random.seed(13)
|
|
|
|
|
np.random.shuffle(idx)
|
|
|
|
|
X = X[idx]
|
|
|
|
|
y = y[idx]
|
|
|
|
|
|
|
|
|
|
# standardize
|
|
|
|
|
mean = X.mean(axis=0)
|
|
|
|
|
std = X.std(axis=0)
|
|
|
|
|
X = (X - mean) / std
|
|
|
|
|
|
|
|
|
|
h = .02 # step size in the mesh
|
|
|
|
|
|
2011-08-11 18:17:14 +08:00
|
|
|
clf = DecisionTreeClassifier().fit(X, y)
|
2011-04-02 05:28:20 +08:00
|
|
|
|
|
|
|
|
# create a mesh to plot in
|
|
|
|
|
x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1
|
|
|
|
|
y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1
|
|
|
|
|
xx, yy = np.meshgrid(np.arange(x_min, x_max, h),
|
|
|
|
|
np.arange(y_min, y_max, h))
|
|
|
|
|
|
2011-09-26 01:30:23 +08:00
|
|
|
pl.subplot(2, 3, pairidx + 1)
|
2011-04-02 05:28:20 +08:00
|
|
|
pl.set_cmap(pl.cm.Paired)
|
|
|
|
|
|
|
|
|
|
# Plot the decision boundary. For that, we will asign a color to each
|
|
|
|
|
# point in the mesh [x_min, m_max]x[y_min, y_max].
|
|
|
|
|
Z = clf.predict(np.c_[xx.ravel(), yy.ravel()])
|
|
|
|
|
# Put the result into a color plot
|
|
|
|
|
Z = Z.reshape(xx.shape)
|
|
|
|
|
pl.set_cmap(pl.cm.Paired)
|
|
|
|
|
cs = pl.contourf(xx, yy, Z)
|
|
|
|
|
pl.xlabel(iris.feature_names[pair[0]])
|
|
|
|
|
pl.ylabel(iris.feature_names[pair[1]])
|
|
|
|
|
pl.axis('tight')
|
|
|
|
|
|
|
|
|
|
# Plot also the training points
|
Refactored decision trees and forests to support CART algorithm.
Notable changes:
1) Supports classification and regression
2) 3 classification criteria, 1 regression criterion
3) A new dataset is provided to test regression (Boston House Prices)
4) Weights are removed from the algorithm entirely. If the need for weights can be justified, I would welcome reintroducing them, but for the refactoring I left them out.
5) The subset of dimensions (F) to split on is fixed for the entire tree, not at each node. This is more in line with CART and RandomForests.
6) A max_depth parameter is offered to limit the size of the constructed trees.
7) Randomisation is fixed with python's random module, but can be seeded.
8) For classification, the number of classes must be provided when the tree is constructed. This is because the tree cannot necessarily infer the correct number of labels at the time of training if only a subset of the data is used for individual trees.
9) For classification, labels are not normalised internally. Labels must be provided to the algorithm in the range [0, ..., K)
10) For classification, the leaf nodes retain the distribution of classes. This means that it is possible to query the tree for the probability distribution of a test sample
2011-07-29 19:37:53 +08:00
|
|
|
for i, color in zip(xrange(K), colors):
|
2011-04-02 05:28:20 +08:00
|
|
|
idx = np.where(y == i)
|
|
|
|
|
pl.scatter(X[idx, 0], X[idx, 1], c=color, label=iris.target_names[i])
|
|
|
|
|
pl.axis('tight')
|
|
|
|
|
|
|
|
|
|
pl.suptitle("Decision surface of multi-class decision tree using paired features")
|
|
|
|
|
|
|
|
|
|
pl.legend()
|
|
|
|
|
pl.show()
|
|
|
|
|
|