Supervised Learning In-Depth: Random Forests(随机森林)
以前,我们看到了一个强大的判别分类器** Support Vector Machines **。
在这里,我们将探讨激励另一个强大的算法。 这是一种称为“随机森林”的非参数算法。
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
plt.style.use('seaborn')
激励随机森林:决策树
随机森林是建立在决策树上的“整体学习者”的一个示例。
因此,我们将从讨论决策树本身开始。
决策树是对对象进行分类或标记的非常直观的方法:您只需提出一系列旨在归类到分类的问题:
二进制拆分使此过程非常有效。
与往常一样,诀窍是提出正确的问题。
这就是算法过程的来历:在训练决策树分类器时,算法会查看特征并确定哪些问题(或“拆分”)包含的信息最多。
创建一个决策树
这是scikit-learn中决策树分类器的示例。 我们将从定义一些二维标签数据开始:
from sklearn.datasets import make_blobs
X, y = make_blobs(n_samples=300, centers=4,
random_state=0, cluster_std=1.0)
plt.scatter(X[:, 0], X[:, 1], c=y, s=50, cmap='rainbow');
我们的存储库中有一些便利功能可以帮助您
from fig_code import visualize_tree, plot_tree_interactive
plot_tree_interactive(X, y);
请注意,每次增加深度时,每个节点都会分为两个**,****仅包含单个类的节点除外。
结果是非常快速的“非参数”分类,在实践中可能非常有用。
问题:您对此有任何疑问吗?
决策树和过度拟合
决策树的一个问题是创建“过度拟合”数据的树非常容易。 也就是说,它们足够灵活,可以了解数据而不是信号中的噪声结构! 例如,看一下基于此数据集的两个子集构建的两棵树:
from sklearn.tree import DecisionTreeClassifier
clf = DecisionTreeClassifier()
plt.figure()
visualize_tree(clf, X[:200], y[:200], boundaries=False)
plt.figure()
visualize_tree(clf, X[-200:], y[-200:], boundaries=False)
分类的细节完全不同! 这表示“过度拟合”:当您预测新点的值时,结果更能反映模型中的噪声而不是信号。
估算器合奏:随机森林
解决过度拟合的一种可能方法是使用“合体方法”:这是一种元估计器,它实际上是对许多过度拟合数据的单个估计器的结果进行平均。 出乎意料的是,所得到的估算值比构成它们的单个估算值更加稳健和准确!
最常见的集成方法之一是“随机森林”,其中的集成由许多决策树组成,这些决策树在某种程度上会受到干扰。
关于如何随机化这些树,有大量的理论和先例,但是作为一个例子,让我们想象一下一组估计器适合数据的子集。 我们可以对它们的外观有所了解,如下所示:
def fit_randomized_tree(random_state=0):
X, y = make_blobs(n_samples=300, centers=4,
random_state=0, cluster_std=2.0)
clf = DecisionTreeClassifier(max_depth=15)
rng = np.random.RandomState(random_state)
i = np.arange(len(y))
rng.shuffle(i)
visualize_tree(clf, X[i[:250]], y[i[:250]], boundaries=False,
xlim=(X[:, 0].min(), X[:, 0].max()),
ylim=(X[:, 1].min(), X[:, 1].max()))
from ipywidgets import interact
interact(fit_randomized_tree, random_state=(0, 100));
查看模型的详细信息如何随样本变化,而较大的特征保持不变!
随机森林分类器将执行类似的操作,但是使用所有这些树的组合版本来得出最终答案:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100, random_state=0)
visualize_tree(clf, X, y, boundaries=False);
通过平均100多个随机扰动模型,我们最终得到了一个更适合我们数据的整体模型!
(注意:以上我们通过子采样对模型进行了随机化处理。…随机森林使用更复杂的随机化方法,您可以在[scikit-learn文档](http://scikit-learn.org /stable/modules/ensemble.html#forest))
快速示例:转向回归
以上我们在分类的背景下考虑了随机森林。
在回归的情况下(也就是连续变量而不是分类变量),也可以使随机森林起作用。 用于此的估算器是``sklearn.ensemble.RandomForestRegressor’’。
让我们快速演示如何使用它:
from sklearn.ensemble import RandomForestRegressor
x = 10 * np.random.rand(100)
def model(x, sigma=0.3):
fast_oscillation = np.sin(5 * x)
slow_oscillation = np.sin(0.5 * x)
noise = sigma * np.random.randn(len(x))
return slow_oscillation + fast_oscillation + noise
y = model(x)
plt.errorbar(x, y, 0.3, fmt='o');
xfit = np.linspace(0, 10, 1000)
yfit = RandomForestRegressor(100).fit(x[:, None], y).predict(xfit[:, None])
ytrue = model(xfit, 0)
plt.errorbar(x, y, 0.3, fmt='o')
plt.plot(xfit, yfit, '-r');
plt.plot(xfit, ytrue, '-k', alpha=0.5);
示例:用于分类数字的随机森林
我们之前看到了“手写数字”数据。 让我们在这里使用它来测试SVM和随机森林分类器的功效。
from sklearn.datasets import load_digits
digits = load_digits()
digits.keys()
>>dict_keys(['data', 'target', 'target_names', 'images', 'DESCR'])
X = digits.data
y = digits.target
print(X.shape)
print(y.shape)
>>(1797, 64)
(1797,)
# set up the figure
fig = plt.figure(figsize=(6, 6)) # figure size in inches
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)
# plot the digits: each image is 8x8 pixels
for i in range(64):
ax = fig.add_subplot(8, 8, i + 1, xticks=[], yticks=[])
ax.imshow(digits.images[i], cmap=plt.cm.binary, interpolation='nearest')
# label the image with the target value
ax.text(0, 7, str(digits.target[i]))
from sklearn.model_selection import train_test_split
from sklearn import metrics
Xtrain, Xtest, ytrain, ytest = train_test_split(X, y, random_state=0)
clf = DecisionTreeClassifier(max_depth=11)
clf.fit(Xtrain, ytrain)
ypred = clf.predict(Xtest)
metrics.accuracy_score(ypred, ytest)
>>0.8222222222222222
为了更好的测量,画出混乱矩阵
plt.imshow(metrics.confusion_matrix(ypred, ytest),
interpolation='nearest', cmap=plt.cm.binary)
plt.grid(False)
plt.colorbar()
plt.xlabel("predicted label")
plt.ylabel("true label");