Python 数据科学手册 5.8 决策树和随机森林

简介: 5.8 决策树和随机森林 原文:In-Depth: Decision Trees and Random Forests 译者:飞龙 协议:CC BY-NC-SA 4.0 译文没有得到原作者授权,不保证与原文的意思严格一致。

5.8 决策树和随机森林

原文:In-Depth: Decision Trees and Random Forests

译者:飞龙

协议:CC BY-NC-SA 4.0

译文没有得到原作者授权,不保证与原文的意思严格一致。

之前,我们深入研究了简单的生成分类器(见朴素贝叶斯分类)和强大的辨别分类器(参见支持向量机)。 这里我们来看看另一个强大的算法的动机 - 一种称为随机森林的非参数算法。 随机森林是组合方法的一个例子,这意味着它依赖于更简单估计器的整体聚合结果。 这种组合方法的结果令人惊讶,总和可以大于部分:即,多个估器中的多数表决最终可能比执行表决的任何个体的估计更好! 我们将在以下部分中看到这个例子。 我们从标准导入开始:

%matplotlib inline
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns; sns.set()

随机森林是一个例子,建立在决策树上的组合学习器。 因此,我们将首先讨论决策树本身。

决策树是分类或标注对象的非常直观的方法:您只需要询问一系列问题,它们为弄清楚分类而设计。 例如,如果您想建立一个决策树,来分类您在远足时遇到的动物,则可以构建如下所示的树:

二元分割使其非常有效:在一个结构良好的树中,每个问题都会将选项数量减少一半,即使在大量分类中也很快缩小选项。 当然,这个技巧是决定在每个步骤中要问哪些问题。 在决策树的机器学习实现中,问题通常采用数据中轴对齐分割的形式:即,树中的每个节点使用其中一个特征中的分割值将数据分成两组。 现在来看一个例子。

创建决策树

考虑以下二维数据,它拥有四个标签之一:

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');

根据这些数据建立的一个简单的决策树,将根据一些定量标准,沿着一个或另一个轴线迭代地分割数据,并且在每个级别,根据其中的多数表决来分配新区域的标签。 该图显示了该数据的决策树分类器的前四个级别的可视化:

请注意,在第一次拆分之后,上部分支中的每个点保持不变,因此无需进一步细分此分支。 除了包含所有一种颜色的节点,在每个级别,每个区域再次沿着两个特征之一分裂。

将决策树拟合到我们的数据的这个过程,可以在 Scikit-Learn 中使用DecisionTreeClassifier估计器来完成:

from sklearn.tree import DecisionTreeClassifier
tree = DecisionTreeClassifier().fit(X, y)

让我们写一个简单的辅助函数,帮助我们展示分类器的输出:

def visualize_classifier(model, X, y, ax=None, cmap='rainbow'):
    ax = ax or plt.gca()

    # Plot the training points
    ax.scatter(X[:, 0], X[:, 1], c=y, s=30, cmap=cmap,
               clim=(y.min(), y.max()), zorder=3)
    ax.axis('tight')
    ax.axis('off')
    xlim = ax.get_xlim()
    ylim = ax.get_ylim()

    # fit the estimator
    model.fit(X, y)
    xx, yy = np.meshgrid(np.linspace(*xlim, num=200),
                         np.linspace(*ylim, num=200))
    Z = model.predict(np.c_[xx.ravel(), yy.ravel()]).reshape(xx.shape)

    # Create a color plot with the results
    n_classes = len(np.unique(y))
    contours = ax.contourf(xx, yy, Z, alpha=0.3,
                           levels=np.arange(n_classes + 1) - 0.5,
                           cmap=cmap, clim=(y.min(), y.max()),
                           zorder=1)

    ax.set(xlim=xlim, ylim=ylim)

现在我们可以检测,决策树看起来是什么样子:

visualize_classifier(DecisionTreeClassifier(), X, y)

如果您现在正在运行这个笔记,您可以使用“在线附录”中包含的帮助脚本,来启动决策树构建过程的交互式可视化:

# helpers_05_08 is found in the online appendix
import helpers_05_08
helpers_05_08.plot_tree_interactive(X, y);

请注意,随着深度的增加,我们倾向于获得非常奇怪的分类区域; 例如,在第五层,黄色和蓝色区域之间有一个高而瘦的紫色区域。 很明显,这不是真实的,固有的数据分布结果,更多的是数据的特定采样或噪声属性的结果。 也就是说,这个决策树,即使只有五个层次的深度,显然对我们的数据过拟合了。

决策树和过拟合

这种过度拟合是决策树的一般属性:在树中很容易就走得太深,从而拟合特定数据的细节,而不是抽取它们分布的整体属性。 查看这种过拟合的另一种方法是,查看在不同数据子集上训练的模型 - 例如,在这个图中,我们训练两种不同的树,每种都是原始数据的一半:

很明显,在一些地方,两棵树产生一致的结果(例如在四个角落),而在其他地方,这两棵树给出非常不同的分类(例如,在任何两个簇之间的区域中)。 关键观察是,分类不太确定的地方,会发生不一致,因此通过使用这两种树的信息,我们可能会得到更好的结果!

如果您正在运行这个笔记,以下功能允许您交互显示树的拟合,在数据的随机子集上训练:

# helpers_05_08 is found in the online appendix
import helpers_05_08
helpers_05_08.randomized_tree_interactive(X, y)

正如使用来自两棵树的信息,改善了我们的结果,我们可能希望使用来自许多树的信息,进一步改善我们的结果。

估计器的组合:随机森林

这个概念 - 多个过拟合估计器可以组合,来减少这种过拟合的影响 - 是一种称为装袋的组合方法。 这个方法使用了一组并行估计器,每个都对数据过拟合,并对结果进行平均以找到更好的分类。 随机决策树的一个组合被称为随机森林。

这种类型的装袋分类,可以使用 Scikit-Learn 的BaggingClassifier元估计器手动进行,如下所示:

from sklearn.tree import DecisionTreeClassifier
from sklearn.ensemble import BaggingClassifier

tree = DecisionTreeClassifier()
bag = BaggingClassifier(tree, n_estimators=100, max_samples=0.8,
                        random_state=1)

bag.fit(X, y)
visualize_classifier(bag, X, y)

在这个例子中,我们将每个估计器拟合训练点的 80% 随机子集进行来随机化数据。 在实践中,通过在选择分割的方式中添加一些随机性,来更有效地随机化决策树:这样,所有数据每次都有助于拟合,但是拟合的结果仍然具有所需的随机性。 例如,当确定要分割的特征时,随机化树可以从前几个特征中选择。 您可以在 Scikit-Learn 文档中阅读这些随机策略的更多技术细节和参考。

在 Scikit-Learn 中,随机决策树的优化组合在RandomForestClassifier估计器中实现,它自动地处理所有的随机化。 所有你需要做的是选择一些估计器,它将很快(如果需要则并行)拟合树的组合:

from sklearn.ensemble import RandomForestClassifier

model = RandomForestClassifier(n_estimators=100, random_state=0)
visualize_classifier(model, X, y);

我们看到,通过对超过 100 个随机扰动的模型取平均,我们最终得到一个整体模型,更接近我们关于如何分割参数空间的直觉。

随机森林回归

在上一节中,我们在分类范围内考虑了随机森林。 随机森林也可以用于回归(即连续而不是分类变量)。 用于此的估计器是RandomForestRegressor,并且语法与我们之前看到的非常相似。

考虑以下数据,由快速和慢速振荡的组合产生:

rng = np.random.RandomState(42)
x = 10 * rng.rand(200)

def model(x, sigma=0.3):
    fast_oscillation = np.sin(5 * x)
    slow_oscillation = np.sin(0.5 * x)
    noise = sigma * rng.randn(len(x))

    return slow_oscillation + fast_oscillation + noise

y = model(x)
plt.errorbar(x, y, 0.3, fmt='o');

使用随机森林回归器,我们可以找到最佳拟合曲线,

这里的真实模型以灰色平滑曲线中显示,随机森林模型由红色锯齿曲线显示。 可以看出,非参数随机森林模型足够灵活,可以拟合多周期数据,而不需要指定多周期模型!

示例:随机森林数字分类

早些时候我们快速浏览了手写数字数据(参见 Scikit-Learn 介绍)。 让我们再次使用它,来看看如何在这个上下文中使用随机森林分类器。

from sklearn.datasets import load_digits
digits = load_digits()
digits.keys()
# dict_keys(['target', 'data', 'target_names', 'DESCR', 'images'])

为了提醒我们,我们正在观察什么,我们展示前几个数据点。

# 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.cross_validation import train_test_split

Xtrain, Xtest, ytrain, ytest = train_test_split(digits.data, digits.target,
                                                random_state=0)
model = RandomForestClassifier(n_estimators=1000)
model.fit(Xtrain, ytrain)
ypred = model.predict(Xtest)

我们可以看一看分类器的分类报告:

from sklearn import metrics
print(metrics.classification_report(ypred, ytest))
             precision    recall  f1-score   support

          0       1.00      0.97      0.99        38
          1       1.00      0.98      0.99        44
          2       0.95      1.00      0.98        42
          3       0.98      0.96      0.97        46
          4       0.97      1.00      0.99        37
          5       0.98      0.96      0.97        49
          6       1.00      1.00      1.00        52
          7       1.00      0.96      0.98        50
          8       0.94      0.98      0.96        46
          9       0.96      0.98      0.97        46

avg / total       0.98      0.98      0.98       450

为了更好的度量,绘制混淆矩阵:

from sklearn.metrics import confusion_matrix
mat = confusion_matrix(ytest, ypred)
sns.heatmap(mat.T, square=True, annot=True, fmt='d', cbar=False)
plt.xlabel('true label')
plt.ylabel('predicted label');

我们发现,简单无调整的随机森林,产生了数据的非常准确的分类。

随机森林总结

本节简要介绍了组合估计器的概念,特别是随机森林 - 随机决策树的整体。 随机森林是一个强大的方法,具有几个优点:

  • 训练和预测都非常快,因为底层决策树简单。 此外,两个任务都可以直接并行化,因为各个树是完全独立的实体。
  • 多个树提供了概率分类:估计器之间的多数表决提供了概率估计(在 Scikit-Learn 中使用predict_proba()方法来访问)。
  • 非参数模型是非常灵活的,因此可以在其他估计器拟合不足的任务上表现良好。

随机森林的主要缺点是结果不容易解释:即如果要对分类模型的含义作出总结,随机森林可能不是最佳选择。

相关文章
|
16天前
|
机器学习/深度学习 数据可视化 数据挖掘
探索Python的奥秘:数据科学中的利器
本文将深入探讨Python编程语言在数据科学领域的强大应用。通过简洁易懂的语言,我们将解析Python的核心概念、流行库以及在实际项目中的应用,帮助您理解为何Python成为数据科学家的首选工具。
32 0
|
12天前
|
存储 大数据 索引
解锁Python隐藏技能:构建高效后缀树Suffix Tree,处理大数据游刃有余!
通过构建高效的后缀树,Python程序在处理大规模字符串数据时能够游刃有余,显著提升性能和效率。无论是学术研究还是工业应用,Suffix Tree都是不可或缺的强大工具。
25 6
|
9天前
|
大数据 UED 开发者
实战演练:利用Python的Trie树优化搜索算法,性能飙升不是梦!
在数据密集型应用中,高效搜索算法至关重要。Trie树(前缀树/字典树)通过优化字符串处理和搜索效率成为理想选择。本文通过Python实战演示Trie树构建与应用,显著提升搜索性能。Trie树利用公共前缀减少查询时间,支持快速插入、删除和搜索。以下为简单示例代码,展示如何构建及使用Trie树进行搜索与前缀匹配,适用于自动补全、拼写检查等场景,助力提升应用性能与用户体验。
27 2
|
13天前
|
存储 算法 数据挖掘
高效文本处理新纪元:Python后缀树Suffix Tree,让数据分析更智能!
在大数据时代,高效处理和分析文本信息成为关键挑战。后缀树作为一种高性能的数据结构,通过压缩存储字符串的所有后缀,实现了高效的字符串搜索、最长公共前缀查询等功能,成为文本处理的强大工具。本文探讨Python中后缀树的应用,展示其在文本搜索、重复内容检测、最长公共子串查找、文本压缩及智能推荐系统的潜力,引领数据分析迈入新纪元。虽然Python标准库未直接提供后缀树,但通过第三方库或自定义实现,可轻松利用其强大功能。掌握后缀树,即掌握开启文本数据宝藏的钥匙。
35 5
|
9天前
|
存储 开发者 Python
从理论到实践:Python中Trie树与Suffix Tree的完美结合,开启编程新篇章!
在编程领域,高效的数据结构对于解决问题至关重要。本文通过一个案例分析,介绍如何在Python中结合使用Trie树(前缀树)和Suffix Tree(后缀树)。案例聚焦于开发具备高效拼写检查和文本相似度检测功能的文本编辑器。首先,通过构建Trie树快速检查单词是否存在;接着,利用Suffix Tree检测文本相似度。尽管Python标准库未直接提供Suffix Tree,但可通过第三方库或自定义实现。本文展示了高级数据结构在实际应用中的强大功能,并强调了理论与实践相结合的重要性。
23 1
|
9天前
|
存储 算法 Python
逆袭之路:掌握Python字典树Trie与后缀树,成为技术圈的耀眼新星!
在编程的征途上,每个人都渴望成为那个能够独当一面、解决复杂问题的技术高手。而掌握高级数据结构,如字典树(Trie)与后缀树(Suffix Tree),无疑是你逆袭路上的重要一步。这些数据结构不仅能够提升你的编码技能,还能让你在解决特定问题时游刃有余,从而在技术圈中脱颖而出,成为那颗耀眼的新星。
19 1
|
11天前
|
机器学习/深度学习 数据可视化 TensorFlow
探索Python在数据科学中的应用
这篇文章深入探讨了Python编程语言在数据科学领域的强大应用。从数据处理、分析到可视化,再到机器学习和深度学习,Python因其丰富的库和框架而成为数据科学家的首选工具。文章不仅介绍了Python的基本语法和数据结构,还详细讨论了如何使用Pandas进行数据清洗和预处理,以及NumPy和SciPy在数值计算中的重要性。此外,文章还涵盖了使用Matplotlib和Seaborn进行数据可视化的技巧,以及Scikit-learn和TensorFlow在构建预测模型中的应用。通过综合运用这些工具,数据科学家能够更有效地分析大量复杂的数据集,从而洞察趋势、模式和关联性,支持决策制定和策略优化。
16 2
|
11天前
|
存储 算法 搜索推荐
Python进阶必备:字典树Trie与后缀树Suffix Array,效率提升的神器!
在Python编程中,掌握高效的数据结构对于提升程序性能至关重要。本文将深入探讨两种强大的字符串处理数据结构——字典树(Trie)与后缀数组(Suffix Array)。字典树,又称前缀树,适用于自动补全和拼写检查等功能。例如,在文本编辑器中实现自动补全时,字典树能够即时提供单词补全选项。后缀数组则用于存储字符串的所有后缀并按字典序排序,结合最长公共前缀(LCP)数组,可以高效解决许多字符串问题,如查找最长重复子串等。通过实际案例,我们将展示这两种数据结构的强大功能,帮助你在Python编程中更进一步。
27 2
|
14天前
|
存储 算法 索引
从菜鸟到大神:一文带你彻底搞懂Python中的后缀树Suffix Tree奥秘!
在Python编程中,后缀树是一种高效的数据结构,特别适用于处理复杂的字符串问题,如搜索、最长公共前缀查询及最长重复子串查找等。本文通过问答形式介绍后缀树的基本概念、重要性及其实现方法。后缀树能显著提高字符串处理效率,将传统方法的时间复杂度从O(nm)降至接近O(m)。尽管其构建过程较复杂,但通过手动编写代码或使用第三方库,我们可以在Python中实现这一强大工具。后缀树的应用广泛,涵盖字符串搜索、压缩、生物信息学等多个领域,学习它不仅能帮助解决实际问题,更能提升算法思维和数据结构设计能力。
29 1
|
16天前
|
API 开发者 Python
Python高手修炼手册:精通文件系统操作,掌控I/O管理,提升编程效率
在Python编程中,从初学者成长为高手,关键在于深入理解底层细节并熟练运用高效工具。本文通过对比分析,探讨如何从基础出发,逐步精通文件系统操作与I/O管理,显著提升编程效率。文件系统操作方面,pathlib模块相较于传统的os和os.path模块更为直观易用;在I/O管理上,异步I/O相比同步I/O能大幅提升程序的并发能力和响应速度。通过这些技巧,开发者不仅能优化代码结构,还能预见并解决潜在性能问题,实现从细节到全局的全面提升。
15 3
下一篇
无影云桌面