先睹为快
from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
iris = load_iris()
X = iris.data[:, 2:] # 花瓣的长度和宽度
y = iris.target
tree_clf = DecisionTreeClassifier(max_depth=2, random_state=42)
tree_clf.fit(X, y)
from matplotlib.colors import ListedColormap
def plot_decision_boundary(clf, X, y, axes=[0, 7.5, 0, 3], iris=True, legend=False, plot_training=True):
x1s = np.linspace(axes[0], axes[1], 100)
x2s = np.linspace(axes[2], axes[3], 100)
x1, x2 = np.meshgrid(x1s, x2s)
X_new = np.c_[x1.ravel(), x2.ravel()]
y_pred = clf.predict(X_new).reshape(x1.shape)
custom_cmap = ListedColormap(['#fafab0','#9898ff','#a0faa0'])
plt.contourf(x1, x2, y_pred, alpha=0.3, cmap=custom_cmap)
if not iris:
custom_cmap2 = ListedColormap(['#7d7d58','#4c4c7f','#507d50'])
plt.contour(x1, x2, y_pred, cmap=custom_cmap2, alpha=0.8)
if plot_training:
plt.plot(X[:, 0][y==0], X[:, 1][y==0], "yo", label="Iris-Setosa")
plt.plot(X[:, 0][y==1], X[:, 1][y==1], "bs", label="Iris-Versicolor")
plt.plot(X[:, 0][y==2], X[:, 1][y==2], "g^", label="Iris-Virginica")
plt.axis(axes)
if iris:
plt.xlabel("Petal length", fontsize=14)
plt.ylabel("Petal width", fontsize=14)
else:
plt.xlabel(r"$x_1$", fontsize=18)
plt.ylabel(r"$x_2$", fontsize=18, rotation=0)
if legend:
plt.legend(loc="lower right", fontsize=14)
plt.figure(figsize=(8, 4))
plot_decision_boundary(tree_clf, X, y)
plt.plot([2.45, 2.45], [0, 3], "k-", linewidth=2)
plt.plot([2.45, 7.5], [1.75, 1.75], "k--", linewidth=2)
plt.plot([4.95, 4.95], [0, 1.75], "k:", linewidth=2)
plt.plot([4.85, 4.85], [1.75, 3], "k:", linewidth=2)
plt.text(1.40, 1.0, "Depth=0", fontsize=15)
plt.text(3.2, 1.80, "Depth=1", fontsize=13)
plt.text(4.05, 0.5, "(Depth=2)", fontsize=11)
plt.show()
tree_clf.predict_proba([[5, 1.5]])
# array([[0. , 0.90740741, 0.09259259]])
tree_clf.predict([[5, 1.5]])
# array([1])
决策树可视化
上面例子的决策树决策树的众多特性之一就是, 它不需要太多的数据预处理, 尤其是不需要进行特征的缩放或者归一化。
- 节点的 samples 属性统计出它应用于多少个训练样本实例。
- 节点的 value 属性表示这个节点对于每一个类别的样例有多少个。
- 节点的 Gini 属性用于测量它的纯度:如果一个节点包含的所有训练样例全都是同一类别的,我们就说这个节点是纯的( Gini=0 )。
- 如果将 max_depth 设置为3,两个深度为 2 的节点,每个都将会添加另一个决策边界(用虚线表示)。
- 估计分类概率:决策树还可以估计某个实例属于特定类 k 的概率:首先遍历树来查找此实例的叶节点,然后它返回此节点中类 k 的训练实例的比例。(如深度为 2 的左节点,三个分类分别为0%(0/54),90.7%(49/54),9.3%(5/54) )
Scikit-Learn 用的是 CART 算法, CART 算法仅产生二叉树:每一个非叶节点总是只有两个子节点(只有是或否两个结果)。然而,像 ID3 这样的算法可以产生超过两个子节点的决策树模型。
CART训练算法
分裂回归树(Classification And Regression Tree,简称 CART)算法训练决策树(也叫“增长树”)。
首先使用单个特征和阈值(例如,“花瓣长度 ≤2.45cm ”)将训练集分成两个子集。它如何选择和呢?它寻找到能够产生最纯粹的子集一对 ,使得成本函数最小。
- CART 算法是一种贪婪算法:它贪婪地搜索最高级别的最佳分割方式,然后在每个深度重复该过程。 它不检查分割是否能够在几个级别中的全部分割可能中找到最佳方法。贪婪算法通常会产生一个相当好的解决方法,但它不保证这是全局中的最佳解决方案。
- 不幸的是,找到最优树是一个 NP 完全问题,它需要 时间。 这就是为什么必须设置一个合理的而不是最佳的解决方案。
信息熵 entropy
通常,算法使用 Gini 不纯度来进行检测, 但是你也可以通过将标准超参数设置为 "entropy" 来使用熵不纯度进行检测。
这里熵的概念是源于热力学中分子混乱程度的概念,当分子井然有序的时候,熵值接近于 0。
熵这个概念后来逐渐被扩展到了各个领域,其中包括香农的信息理论,这个理论被用于测算一段信息中的平均信息密度。当所有信息相同的时候熵被定义为零。
在机器学习中,熵经常被用作不纯度的衡量方式,当一个集合内只包含一类实例时, 我们称为数据集的熵为 0。
到底应该使用 Gini 指数还是熵呢? 事实上大部分情况都没有多大的差别:他们会生成类似的决策树。
基尼指数计算稍微快一点,所以这是一个很好的默认值。但是,也有的时候它们会产生不同的树,基尼指数会趋于在树的分支中将最多的类隔离出来,而熵指数趋向于产生略微平衡一些的决策树模型。
正则化参数
- min_samples_split (节点在被分裂之前必须具有的最小样本数)
- min_samples_leaf (叶节点必须具有的最小样本数)
- min_weight_fraction_leaf (和 min_samples_leaf 相同,但表示为加权总数的一小部分实例)
- max_leaf_nodes (叶节点的最大数量)和max_features (在每个节点被评估是否分裂的时候,具有的最大特征数量)。
- 增加 min_* hyperparameters 或者减少 max_* hyperparameters 会使模型正则化。
from sklearn.datasets import make_moons
Xm, ym = make_moons(n_samples=100, noise=0.25, random_state=53)
deep_tree_clf1 = DecisionTreeClassifier(random_state=42)
deep_tree_clf2 = DecisionTreeClassifier(min_samples_leaf=4, random_state=42)
deep_tree_clf1.fit(Xm, ym)
deep_tree_clf2.fit(Xm, ym)
plt.figure(figsize=(11, 4))
plt.subplot(121)
plot_decision_boundary(deep_tree_clf1, Xm, ym, axes=[-1.5, 2.5, -1, 1.5], iris=False)
plt.title("No restrictions", fontsize=16)
plt.subplot(122)
plot_decision_boundary(deep_tree_clf2, Xm, ym, axes=[-1.5, 2.5, -1, 1.5], iris=False)
plt.title("min_samples_leaf = {}".format(deep_tree_clf2.min_samples_leaf), fontsize=14)
plt.show()
min_sample_leaf
回归
# Quadratic training set + noise
np.random.seed(42)
m = 200
X = np.random.rand(m, 1)
y = 4 * (X - 0.5) ** 2
y = y + np.random.randn(m, 1) / 10
from sklearn.tree import DecisionTreeRegressor
tree_reg1 = DecisionTreeRegressor(random_state=42, max_depth=2)
tree_reg2 = DecisionTreeRegressor(random_state=42, max_depth=3)
tree_reg1.fit(X, y)
tree_reg2.fit(X, y)
def plot_regression_predictions(tree_reg, X, y, axes=[0, 1, -0.2, 1], ylabel="$y$"):
x1 = np.linspace(axes[0], axes[1], 500).reshape(-1, 1)
y_pred = tree_reg.predict(x1)
plt.axis(axes)
plt.xlabel("$x_1$", fontsize=18)
if ylabel:
plt.ylabel(ylabel, fontsize=18, rotation=0)
plt.plot(X, y, "b.")
plt.plot(x1, y_pred, "r.-", linewidth=2, label=r"$\hat{y}$")
plt.figure(figsize=(11, 4))
plt.subplot(121)
plot_regression_predictions(tree_reg1, X, y)
for split, style in ((0.1973, "k-"), (0.0917, "k--"), (0.7718, "k--")):
plt.plot([split, split], [-0.2, 1], style, linewidth=2)
plt.text(0.21, 0.65, "Depth=0", fontsize=15)
plt.text(0.01, 0.2, "Depth=1", fontsize=13)
plt.text(0.65, 0.8, "Depth=1", fontsize=13)
plt.legend(loc="upper center", fontsize=18)
plt.title("max_depth=2", fontsize=14)
plt.subplot(122)
plot_regression_predictions(tree_reg2, X, y, ylabel=None)
for split, style in ((0.1973, "k-"), (0.0917, "k--"), (0.7718, "k--")):
plt.plot([split, split], [-0.2, 1], style, linewidth=2)
for split in (0.0458, 0.1298, 0.2873, 0.9040):
plt.plot([split, split], [-0.2, 1], "k:", linewidth=1)
plt.text(0.3, 0.5, "Depth=2", fontsize=13)
plt.title("max_depth=3", fontsize=14)
plt.show()
决策树回归
CART 算法的工作方式与之前处理分类模型基本一样,不同之处在于,现在不再以最小化不纯度的方式分割训练集,而是试图以最小化 MSE 的方式分割训练集。
不稳定性
决策树很喜欢设定正交化的决策边界,(所有边界都是和某一个轴相垂直的),这使得它对训练数据集的旋转很敏感。解决这个难题的一种方式是使用 PCA 主成分分析,这样通常能使训练结果变得更好一些。
对 moons 数据集进行决策树训练并优化模型
from sklearn.datasets import make_moons
X, y = make_moons(n_samples=10000, noise=0.4, random_state=42)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
from sklearn.model_selection import GridSearchCV
params = {'max_leaf_nodes': list(range(2, 100)), 'min_samples_split': [2, 3, 4]}
grid_search_cv = GridSearchCV(DecisionTreeClassifier(random_state=42), params, n_jobs=-1, verbose=1)
grid_search_cv.fit(X_train, y_train)
grid_search_cv.best_estimator_
'''
DecisionTreeClassifier(class_weight=None, criterion='gini', max_depth=None,
max_features=None, max_leaf_nodes=17,
min_impurity_decrease=0.0, min_impurity_split=None,
min_samples_leaf=1, min_samples_split=2,
min_weight_fraction_leaf=0.0, presort=False, random_state=42,
splitter='best')
'''
from sklearn.metrics import accuracy_score
y_pred = grid_search_cv.predict(X_test)
accuracy_score(y_test, y_pred)
# 0.8695
网友评论