这个分析笔记由Jake Vanderplas编辑汇总。 源代码和license文件在GitHub。 中文翻译由派兰数据在派兰大数据分析平台上完成。 源代码在GitHub上。
之前我们已经了解过了强大的判别分类器,支持向量机。在这里我们要看一看另一种强大的算法。这个算法是一个非参数方法,叫随机森林。
In [1]:
%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
# 使用seaborn的默认设置
import seaborn as sns; sns.set()
随机森林是在决策树的基础上的一个集成学习算法。所以我们从讨论决策树开始我们的介绍,
决策树是一个非常直观的,给对象分类或者是贴标签的方法:您仅仅需要提出一系列的问题并回答它们,模型会根据问题的答案逐渐完善。
In [2]:
import fig_code
fig_code.plot_example_decision_tree()
In [3]:
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');
我们在sklearn的库中有一些可以提供帮助的函数:
In [4]:
from fig_code import visualize_tree, plot_tree_interactive
现在使用 IPython 的interact
(在 IPython2.0+ 中可以使用,且需要一个实时的核)。我们可以看到决策树的分隔:
In [5]:
plot_tree_interactive(X, y);
注意到随着深度的增加,除了那些本来只包含一类的点之外,每一个数据集都被成功的划分。 这是个非常快的无参数分类过程,在实际运用中非常实用。
问题:您看到这里隐含的缺陷了吗?
In [6]:
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)
两种分类模型的细节完全不一样!这就是过拟合的一个直观展示:当你采用你的模型去预测一个新的点的时候,这个模型更容易被数据中的噪声而不是数据本身所影响。
In [7]:
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 IPython.html.widgets import interact
interact(fit_randomized_tree, random_state=[0, 100]);
我们可以看到,不管细节怎么随着函数的改变而改变,大的特征总是保持不变的!随机森林的分类器会做类似的事情,只是它会把所有的模型组合起来去得到最后的结果:
In [8]:
from sklearn.ensemble import RandomForestClassifier
clf = RandomForestClassifier(n_estimators=100, random_state=0)
visualize_tree(clf, X, y, boundaries=False);
通过对100个随机的模型取平均,我们得到了一个可以更好拟合我们的数据的模型!
(注意: 上面我们通过下采样的方式对我们的模型做了随机。随机森林运用了更加成熟的方法,对于这点您可以参考 scikit-learn documentation)
In [9]:
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');
In [10]:
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);
从中你可以看到,这个非参数的随机森林的模型足够去拟合多周期的数据,甚至都不需要我们为它指定一个多周期的模型!
In [11]:
from sklearn.datasets import load_digits
digits = load_digits()
digits.keys()
Out[11]:
In [12]:
X = digits.data
y = digits.target
print(X.shape)
print(y.shape)
为了让我们更好的记起来手写数字数据集,我们先将其中一部分画出来:
In [13]:
# 设置绘图
fig = plt.figure(figsize=(6, 6)) # 图片大小是以英寸(inches)计算的
fig.subplots_adjust(left=0, right=1, bottom=0, top=1, hspace=0.05, wspace=0.05)
# 绘制这些数字: 每个图像是 8x8 像素点阵的
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,就是target值)
ax.text(0, 7, str(digits.target[i]))
我们可以使用决策树来快速的对数字进行分类:
In [14]:
from sklearn.cross_validation 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)
我们可以检查一下这个分类器的准确率:
In [15]:
metrics.accuracy_score(ypred, ytest)
Out[15]:
为了更好的看出分类器的性能,我们画出混淆矩阵:
In [16]:
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");
In [ ]: