如何用 Python 从零开始实现随机森林

决策树可能会因高方差而导致其结果对所使用的训练数据过于敏感。

通过从训练数据样本中构建多个模型(称为 bagging)可以降低这种方差,但这些树的关联性很强。

随机森林是 bagging 的一种扩展,它除了根据训练数据的多个样本构建树之外,还限制了可用于构建树的特征,从而迫使树之间产生差异。这反过来可以提高性能。

在本教程中,您将了解如何用 Python 从零开始实现随机森林算法。

完成本教程后,您将了解:

  • bagging 决策树与随机森林算法之间的区别。
  • 如何构建具有更高方差的 bagging 决策树。
  • 如何将随机森林算法应用于预测建模问题。

立即启动您的项目,阅读我的新书《从零开始的机器学习算法》,书中包含分步教程以及所有示例的Python源代码文件。

让我们开始吧。

  • 更新于 2017 年 1 月:更改了 `cross_validation_split()` 中 `fold_size` 的计算,使其始终为整数。修复了 Python 3 的问题。
  • 2017 年 2 月更新:修复了 build_tree 中的一个 bug。
  • 2017 年 8 月更新:修复了 Gini 计算中的一个 bug,添加了按组大小对组 Gini 分数进行加权的功能(感谢 Michael!)。
  • 2018 年 8 月更新:测试并更新以与 Python 3.6 配合使用。
How to Implement Random Forest From Scratch in Python

如何用 Python 从零开始实现随机森林
照片由 InspireFate Photography 提供,保留部分权利。

描述

本节简要介绍了随机森林算法和本教程使用的声纳数据集。

随机森林算法

决策树在每一步都通过贪婪地选择数据集中的最佳分裂点。

如果不进行剪枝,该算法会使决策树容易产生高方差。这种高方差可以通过创建具有不同训练数据集样本(问题的不同视角)的多个树并组合它们的预测来加以利用并降低。这种方法称为 bootstrap aggregation,简称 bagging。

bagging 的一个限制是,每棵树的创建都使用了相同的贪婪算法,这意味着每棵树中很可能选择相同的或非常相似的分裂点,从而使不同的树非常相似(树将是相关的)。这反过来又使得它们的预测相似,从而削弱了最初追求的方差。

我们可以通过限制贪婪算法在创建树时每个分裂点可以评估的特征(行)来强制决策树产生差异。这就是随机森林算法。

与 bagging 类似,将采用训练数据的多个样本,并对每个样本训练不同的树。不同之处在于,在数据中进行分裂并添加到树中的每个点,只能考虑固定数量的属性。

对于分类问题,也就是本教程将要探讨的问题类型,用于分裂的属性数量限制为输入特征总数的平方根。

这个小小的改变带来的结果是,树彼此之间的差异更大(不相关),预测也更多样化,并且组合预测的性能通常优于单独的树或单独的 bagging。

声纳数据集

本教程中将使用的数据集是声纳数据集。

这是一个描述声纳信号返回在不同表面上反射的数据集。60个输入变量是不同角度的返回强度。这是一个二元分类问题,需要一个模型来区分岩石和金属圆柱体。共有208个观测。

这是一个众所周知的数据集。所有变量都是连续的,通常在 0 到 1 的范围内。输出变量是一个字符串,“M”代表水雷,“R”代表岩石,需要转换为整数 1 和 0。

通过预测数据集中观测值最多的类别(M 或地雷),零规则算法可以达到 53% 的准确率。

您可以在 UCI 机器学习存储库了解有关此数据集的更多信息。

免费下载数据集,并将其放置在您的工作目录中,文件名为 **sonar.all-data.csv**。

教程

本教程分为 2 个步骤。

  1. 计算分裂点。
  2. 声纳数据集案例研究。

这些步骤提供了您将随机森林算法实现并应用于自己的预测建模问题所需的基础。

1. 计算分裂点

在决策树中,分裂点的选择是通过查找属性及其值来找到成本最低的。

对于分类问题,这种成本函数通常是 Gini 指数,它计算分裂点创建的数据组的纯度。Gini 指数为 0 表示完美纯度,其中类值在两个组中完美分离,在二分类问题中是这样。

在决策树中找到最佳分裂点涉及评估训练数据集中每个输入变量每个值对应的成本。

对于 bagging 和随机森林,此过程将在带有放回的训练数据集样本上执行。带放回抽样意味着同一行可能被选择并添加到样本中不止一次。

我们可以更新随机森林的此过程。与其枚举搜索中所有输入属性的值来查找成本最低的分裂点,不如创建要考虑的输入属性的样本。

这个输入属性样本可以随机选择且不放回,这意味着在查找成本最低的分裂点时,每个输入属性只需要考虑一次。

下面是一个名为 get_split() 的函数,它实现了此过程。它接受一个数据集和一个要评估的固定数量的输入特征作为输入参数,其中数据集可以是实际训练数据集的样本。

辅助函数 test_split() 用于按候选分裂点分割数据集,gini_index() 用于通过创建的行组评估给定分裂点的成本。

我们可以看到,通过随机选择特征索引并将其添加到列表(称为 features)中来创建特征列表,然后对该特征列表进行枚举,并评估训练数据集中的特定值作为分裂点。

现在我们知道了决策树算法如何修改以用于随机森林算法,我们可以将其与 bagging 的实现结合起来,并应用于实际数据集。

2. 声纳数据集案例研究

在本节中,我们将把随机森林算法应用于声纳数据集。

该示例假设数据集的 CSV 副本位于当前工作目录中,文件名为 sonar.all-data.csv

首先加载数据集,将字符串值转换为数字,并将输出列从字符串转换为 0 和 1 的整数值。这是通过辅助函数 load_csv()str_column_to_float()str_column_to_int() 来加载和准备数据集实现的。

我们将使用 k 折交叉验证来估计模型在未见过的数据上的性能。这意味着我们将构建和评估 k 个模型,并将性能估计为平均模型误差。分类准确率将用于评估每个模型。这些行为由辅助函数 cross_validation_split()accuracy_metric()evaluate_algorithm() 提供。

我们还将使用一个分类回归树 (CART) 算法的实现,该算法已针对 bagging 进行调整,包括用于将数据集分割成组的辅助函数 test_split(),用于评估分裂点的 gini_index(),我们修改过的 get_split() 函数(在前一步中讨论过),用于创建单个决策树的 to_terminal()split()build_tree(),用于使用决策树进行预测的 predict(),用于创建训练数据集子样本的 subsample(),以及用于使用决策树列表进行预测的 bagging_predict()

开发了一个名为 random_forest() 的新函数,该函数首先从训练数据集的子样本中创建决策树列表,然后使用它们进行预测。

正如我们上面所说,随机森林与 bagging 决策树之间的关键区别在于创建树的方式上有一个小的改动,这里是在 get_split() 函数中。

完整的示例如下所示。

交叉验证使用了 5 的 k 值,每次迭代让每个折叠有 208/5 = 41.6 或略高于 40 条记录进行评估。

构建了深度为 10 的深层树,每个节点中的最小训练行数为 1。创建的训练数据集样本大小与原始数据集相同,这是随机森林算法的默认期望。

在每次分裂点考虑的特征数量设置为 sqrt(num_features) 或 sqrt(60)=7.74 四舍五入为 7 个特征。

评估了 3 种不同数量的树进行比较,显示随着树的数量增加,技能也在提高。

运行示例会为每种配置打印每个折叠的分数和平均分数。

扩展

本节列出了您可能感兴趣的本教程的扩展内容。

  • 算法调优。本教程中使用的配置是通过一些试错找到的,但并未优化。尝试更多的树、更多的特征,甚至是不同的树配置来提高性能。
  • 更多问题。将该技术应用于其他分类问题,甚至通过新的成本函数和新的组合树预测的方法来适应回归问题。

你尝试过这些扩展吗?
在下面的评论中分享您的经验。

回顾

在本教程中,您将了解如何从头开始实现随机森林算法。

具体来说,你学到了:

  • 随机森林与装袋决策树的区别。
  • 如何更新决策树的创建以适应随机森林过程。
  • 如何将随机森林算法应用于真实的预测建模问题。

你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。

了解如何从零开始编写算法!

Machine Learning Algorithms From Scratch

没有库,只有 Python 代码。

...附带真实世界数据集的逐步教程

在我的新电子书中探索如何实现
从零开始实现机器学习算法

它涵盖了 18 个教程,包含 12 种顶级算法的所有代码,例如
线性回归、k-近邻、随机梯度下降等等……

最后,揭开
机器学习算法的神秘面纱

跳过学术理论。只看结果。

查看内容

129 条评论 如何用 Python 从头实现随机森林

  1. Marco 2016年12月3日 上午7:06 #

    嗨,Jason,
    首先,感谢您在此网站上的工作——我发现这是一个很好的资源,可以开始我的 Python 机器学习探索!

    现在,我正在学习您的 Python 机器学习迷你课程,目前到了第 9 课:算法的抽样检查。您建议测试随机森林,这让我找到了这篇博文,我正在尝试运行其中的示例,但遇到了以下错误

    回溯(最近一次调用)
    File “test.py”, line 203, in
    scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features)
    File “test.py”, line 57, in evaluate_algorithm
    folds = cross_validation_split(dataset, n_folds)
    File “test.py”, line 42, in cross_validation_split
    index = randrange(len(dataset_copy))
    File “//anaconda/lib/python3.5/random.py”, line 186, in randrange
    raise ValueError(“empty range for randrange()”)
    ValueError: randrange() 的范围为空

    我花了将近一个小时试图找出我可能做错了什么……不幸的是,我真的很不擅长编码,所以我发现这非常困难。我认为我已经缩小到以下可能性
    1. 可能是 evaluate_algorithm 函数的定义有问题?
    2. 可能是使用 python 3.5.2 中的 randrange 有问题?
    3. 可能是“dataset”定义有问题?

    我认为要么是 #1,因为代码在第 202 行之前都没有问题,要么是 #3,因为 dataset 是从返回的错误行中常见的线索……?

    非常感谢您的指导!

    再次感谢!
    marco

    • Dionysis 2017年6月4日 上午4:05 #

      你好,

      是否可以轻松地将此实现改编以适应特征向量的元组?

      谢谢,
      D.

    • Jeffrey Grover 2017年7月28日 上午8:30 #

      嗨 Jason,我能够运行代码并获得与本页面上发布的结果。我的问题是接下来做什么?如何使用这些结果对新数据进行分类?

      谢谢 Jeff

  2. Marco 2016年12月4日 下午10:09 #

    搞定了!是 Python 3.5.2 的问题。我切换到 2.7 就好了!

    谢谢
    marco

  3. srikanth 2016年12月8日 下午9:42 #

    回溯(最近一次调用)
    File “rf2.py”, line 203, in
    scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features)
    File “rf2.py”, line 68, in evaluate_algorithm
    predicted = algorithm(train_set, test_set, *args)
    File “rf2.py”, line 181, in random_forest
    tree = build_tree(sample, max_depth, min_size, n_features)
    File “rf2.py”, line 146, in build_tree
    split(root, max_depth, min_size, n_features, 1)
    File “rf2.py”, line 120, in split
    left, right = node[‘groups’]
    TypeError: ‘NoneType’ object is not iterable

    • Mary 2020年6月25日 下午10:35 #

      我遇到了同样的问题

  4. beedotkiran 2016年12月21日 上午7:00 #

    在 Python 3.x 中也有效。第 45 行的除法
    fold_size = len(dataset) / n_folds
    产生一个浮点数,当 dataset_copy 的长度为零时,它仍然有效。randrange(0) 会导致此错误。

    将此行替换为
    fold_size = len(dataset) // n_folds
    会得到一个整数,并且循环可以正常执行。

    • Jason Brownlee 2016年12月21日 上午8:50 #

      谢谢 beedotkiran。

      我建议强制转换结果,以防 Python 初学者不熟悉双斜杠运算符。

      • Jason Brownlee 2017年1月3日 上午9:54 #

        我已经更新了上面示例中的 cross_validation_split() 函数,以解决 Python 3 的问题。

  5. Jake Rage 2017年1月28日 下午1:34 #

    这是一个非常棒的教程,非常感谢您花时间来做这件事!我想知道您是否对序列化或将树用于其他类似数据集有任何建议,腌制(pickling)对这种结构有用吗?谢谢您的帮助!

    • Jason Brownlee 2017年2月1日 上午10:06 #

      嗨 Jake,对学习到的对象使用 pickle 会是一个不错的起点。

  6. Alessandro 2017年2月25日 上午12:25 #

    嗨 Jason,很棒的教程!只是关于 build_tree 函数的一个问题:当您评估树的根时,您不应该使用训练样本而不是整个数据集吗?

    我的意思是

    root = get_split(train, n_features) 而不是
    root = get_split(dataset, n_features)

    我还可以问一下,如果您想将此算法改编为回归问题而不是分类问题,那么主要区别是什么?

    非常感谢!祝您一切顺利

    • Alessandro 2017年2月25日 上午12:28 #

      抱歉,我没看到您已经解决了这个问题。

  7. Mike 2017年4月11日 上午1:39 #

    你好 Jason,很好的方法。我想知道您是否有关于将上述代码转换为支持多标签分类的技巧。
    非常感谢!!!

  8. Steve 2017年5月3日 下午4:29 #

    你好 Jason,我喜欢这种允许人们“深入了解”这些机器学习方法的方法。我期待以这种方式学习更多机器学习方法。

    随机森林对我来说是全新的。我有一个可以利用随机森林回归的数据集。我想知道需要进行哪些更改才能将随机森林分类代码(上面)转换为随机森林回归。 Alessandro 之前也问过这个问题,但我没有理解他的回答。据我所知,随机森林回归的解释并不清楚。

    谢谢。

  9. Steve Hansen 2017年6月9日 上午10:29 #

    Jason,

    感谢关于随机森林回归的建议。

    在声纳数据集上,我绘制了数据中 60x60 的相关矩阵。许多连续的行,甚至不那么接近的行,都高度相关。例如,第 17 行和第 18 列的相关性如下

    观察数:131
    自由度:2

    R平方:0.870
    RMSE:0.1046
    F统计量 863。

    并且第 14 列和第 15 列的相关性为

    观察数:131
    自由度:2

    R平方:0.8554
    RMSE:0.0708
    F统计量 763。

    这种相关性对随机森林的使用有什么影响?如何消除或衡量相关性的影响?

    另外,对于这个数据集,我获得了以下结果

    n_folds = 5
    max_depth = 12
    min_size = 1
    sample_size = 0.75
    for n_trees in [1, 5, 19]

    71.875%, 73.438%, 82.031%

    感谢您的辛勤工作。我正在努力吸收所有内容。

    • Jason Brownlee 2017年6月10日 上午8:12 #

      结果不错。

      我不认为 RF 会受到高度相关特征的太大影响。尽管如此,尝试删除一些特征,看看它们对模型技能的影响。我很想听听您的发现。

    • dhrumil 2018年1月30日 下午7:15 #

      你是如何找到相关性的,为什么它会造成问题?我对此不太了解,所以我想从像您这样的专家那里了解这些。谢谢。

  10. danniel 2017年6月17日 上午12:52 #

    你好 Jason,感谢您提供的精彩教程,您能解释一下以下几点吗?
    1. 这行代码的作用是什么:row_copy[-1] = None:因为它在没有这行代码的情况下也能完美运行
    2. 当我尝试 n_trees=[3,5,10] 时,返回的结果是准确性随着树的数量增加而降低:
    Trees: 3
    Scores: [63.41463414634146, 51.21951219512195, 68.29268292682927, 68.29268292682927, 63.41463414634146]
    Mean Accuracy: 62.927%
    Trees: 5
    Scores: [65.85365853658537, 60.97560975609756, 60.97560975609756, 60.97560975609756, 58.536585365853654]
    Mean Accuracy: 61.463%
    Trees: 10
    Scores: [48.78048780487805, 60.97560975609756, 58.536585365853654, 70.73170731707317, 53.65853658536586]
    Mean Accuracy: 58.537%

  11. danniel 2017年6月18日 上午12:55 #

    您建议我如何使用这个:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/learn/random_forest_mnist.py
    或者我可以使用它吗,这与您所做的相同吗?

  12. chris 2017年6月19日 下午7:02 #

    做得好!进行回归问题时,我应该使用哪种成本函数?

    • Jason Brownlee 2017年6月20日 上午6:36 #

      好问题,可以考虑均方误差或平均绝对误差。

  13. joe 2017年6月20日 上午12:30 #

    test_split 返回两个值,但这里 groups = test_split(index, row[index], dataset) 只有一个变量,有人能解释一下吗?非常感谢!

    • Jason Brownlee 2017年6月20日 上午6:37 #

      返回的数组被赋值给一个名为 groups 的变量。

  14. Chiky 2017年7月6日 下午5:13 #

    嗨,Jason,
    我正在通过您的示例来学习随机森林。但在运行代码时,我遇到了一个错误。我正在使用Ipython Notebook。

    in split(node, max_depth, min_size, n_features, depth)
    6 # Create child splits for a node or make terminal
    7 def split(node, max_depth, min_size, n_features, depth)
    —-> 8 left, right = node[‘groups’]
    9 del(node[‘groups’])
    10 # check for a no split

    TypeError: ‘NoneType’ object is not iterable

    请帮忙。

    • Chiky 2017年7月6日 下午5:19 #

      错误链列表

      TypeError Traceback (most recent call last)
      in ()
      16 n_features = int(sqrt(len(dataset[0])-1))
      17 for n_trees in [1, 5, 10]
      —> 18 scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features)
      19 print(‘Trees: %d’ % n_trees)
      20 print(‘Scores: %s’ % scores)

      在 evaluate_algorithm(dataset, algorithm, n_folds, *args)中
      12 test_set.append(row_copy)
      13 row_copy[-1] = None
      —> 14 predicted = algorithm(train_set, test_set, *args)
      15 actual = [row[-1] for row in fold]
      16 accuracy = accuracy_metric(actual, predicted)

      in random_forest(train, test, max_depth, min_size, sample_size, n_trees, n_features)
      18 for i in range(n_trees)
      19 sample = subsample(train, sample_size)
      —> 20 tree = build_tree(sample, max_depth, min_size, n_features)
      21 trees.append(tree)
      22 predictions = [bagging_predict(trees, row) for row in test]

      in build_tree(train, max_depth, min_size, n_features)
      2 def build_tree(train, max_depth, min_size, n_features)
      3 root = get_split(train, n_features)
      —-> 4 split(root, max_depth, min_size, n_features, 1)
      5 return root
      6

      in split(node, max_depth, min_size, n_features, depth)
      6 # Create child splits for a node or make terminal
      7 def split(node, max_depth, min_size, n_features, depth)
      —-> 8 left, right = node[‘groups’]
      9 del(node[‘groups’])
      10 # check for a no split

      TypeError: ‘NoneType’ object is not iterable

    • Jason Brownlee 2017年7月9日 上午10:25 #

      抱歉,我不使用 Notebook。请确认 Python 版本为 2。

  15. Danny Shterman 2017年7月13日 下午11:53 #

    在计算基尼指数之前,数据集是否应该按某个特征排序?

  16. Tatiana 2017年7月14日 上午9:50 #

    你好,Jason
    非常感谢您的课程。您的代码运行完美。
    我现在正在尝试使用另一个包含字符串值的数据集。并因此遇到困难。这可能吗?我一直收到无法将字符串转换为整数的错误。

    • Jason Brownlee 2017年7月15日 上午9:34 #

      谢谢。

      您必须将字符串转换为整数或实数值。也许您需要使用独热编码?

  17. Danny 2017年7月17日 下午5:40 #

    你好,
    是否需要对每个分裂的加权基尼指数进行求和?
    谢谢
    丹尼

  18. Jeffrey Grover 2017年7月29日 上午6:19 #

    Jason,我已将此协议发布到 YouTube 作为参考 @ https://youtu.be/Appc0Hpnado

    感谢您花时间教我们这种方法!

    杰夫

  19. Wells 2017年8月31日 下午2:47 #

    Jason,您的实现帮助了我很多!但是,我有一个问题:在每次分割时,算法都会从总特征中随机选择一个特征子集,然后选择具有最佳基尼得分的最佳特征。那么,一棵树是否有可能在不同的分裂中使用同一个特征?因为在get_split()中,line index = randrange(len(dataset[0])-1)基本上是从整个池中选取特征。您能解释一下吗?谢谢!

    • Jason Brownlee 2017年9月1日 上午6:41 #

      它不会选择最佳分割,而是选择最佳分割中的一个随机分割。

      如果从基尼得分的角度来看,您可以使用单个特征进行多次分割。

      • Wells 2017年9月1日 下午1:36 #

        是的,我意识到了这一点。谢谢!

  20. Ria 2017年9月22日 上午10:51 #

    rf_model = training(training_data2,RandomForestClassifier())
    print rf_model
    test(rf_model,test_data2)

    RandomForestClassifier(bootstrap=True, class_weight=None, criterion=’gini’,
    max_depth=None, max_features=’auto’, max_leaf_nodes=None,
    min_impurity_split=1e-07, min_samples_leaf=1,
    min_samples_split=2, min_weight_fraction_leaf=0.0,
    n_estimators=10, n_jobs=1, oob_score=False, random_state=None,
    verbose=0, warm_start=False)
    我尝试使用树的数量=1, 5, 10,如您的示例所示,但不起作用,您能告诉我需要进行哪些更改吗?而且,当我设置randomstate = none时,每次执行我的准确率都在变化,但当我设置一个随机状态值时,准确率是相同的。

  21. DATAEXPERT 2017年10月15日 上午4:58 #

    你好,
    我想将代码更改为适用于 90% 的训练数据和 10% 的测试数据,不进行交叉验证。如果我使用 n_folds = 1,我会收到一个错误。我该如何更改代码才能使其正常工作?

  22. Ali 2017年10月28日 上午2:23 #

    我们能否在 MATLAB 中使用 fitctree 实现随机森林?

    有一个函数 TreeBagger 可以实现随机森林。但是,如果我们使用这个函数,我们就无法控制每个单独的树。我们能否使用 MATLAB 函数 fitctree(它构建决策树)来实现随机森林?非常感谢。

  23. Kuber Jain 2017年11月22日 下午12:06 #

    嗨,Jason,

    我正在尝试使用 RF 解决分类问题,每次我运行 RandomForestClassifier 对我的训练数据时,特征重要性都会显示每次运行的模型都不同。我如何才能确保每次运行模型时都获得相同的排名前 5 的特征?请告诉我。

    model_rc = RandomForestClassifier(n_estimators=10,max_depth=None,min_samples_split=2,random_state=0)
    rc_fit=model_rc.fit(X_train, y_train.values.ravel())

  24. Khin 2018年1月3日 上午2:15 #

    我想知道 sklearn 随机森林和自己实现的随机森林算法有什么区别。sklearn 随机森林有什么弱点或问题吗?

    • Jason Brownlee 2018年1月3日 上午5:39 #

      我建议您仅出于学习目的自己实现该算法,我预计 sklearn 的实现会更健壮、更高效。

  25. PSN 2018年1月3日 下午5:43 #

    您能实现旋转森林算法吗?

  26. Sterling 2018年1月4日 上午11:01 #

    您的博客和教程在我的整个博士期间都帮助了我。感谢您投入如此多的时间和精力来分享这些信息。

  27. Ioannis 2018年2月5日 上午3:50 #

    亲爱的 Jason,

    非常感谢您的这个实现,太棒了!

    是否可以了解哪些特征对于手头的任务最具辨别力
    以及这些特征各自的重要性程度?
    提前表示感谢!!!

    Jason Brownlee 2018年2月5日 上午7:47 #

  28. 感谢分享!我想知道您的实现有多快。(我猜我应该自己试试。🙂

    嗨,Jason,

    我是一名生物统计学硕士生,正在做一个论文项目,该项目应用了修改版的随机森林(没有现有实现)来解决一个问题。我习惯于 R。我尝试努力改进我的代码,并将部分代码用 C++(通过 Rcpp 包)实现,但它仍然很慢……我注意到 R 或 Python 中的随机森林包都在调用核心是用 C 编写的代码。

    那么,您介意估计一下您的实现与主流实现相比有多快(例如,比 Scikit-learn 慢 10 倍)吗?

    我是 Python 新手。我真的很应该自己试试,但就是忍不住想快速得到这个答案来激励我学习 Python!🙂
    Kehao

    谢谢!

    Jason Brownlee 2018年3月1日 上午6:07 #

    • 它很慢。它仅用于学习目的。

      Kirtika Bhatt 2018年3月23日 上午6:55 #

  29. 我是 Python 新手,正在做一个小型项目来自学。如果您能指导我如何使用此算法来预测某些测试数据的类别,那将非常有帮助。

    Jason Brownlee 2018年3月23日 上午8:28 #

  30. 我可能还会发另一条消息,但不确定是否已发送。

    嗨,Jason,
    我只想感谢您提供信息丰富的网站。
    这篇帖子也非常全面,充满了综合的想法和主题。
    如果 Python 项目可用,我将不胜感激。
    niloofar

    此致,
    Jason Brownlee 2018年4月7日 上午6:22 #

    • samiha 2018年5月24日 下午10:32 #

      谢谢,很高兴它帮到了你!

  31. 请问我该如何评估这个算法!?

    你好
    Jason Brownlee 2018年5月25日 上午9:26 #

  32. 尊敬的 Brownlee 博士,

    恭喜您完成这项了不起的工作,先生。我有一个小问题,先生。您花了多长时间写出如此出色的代码,以及您使用了哪些资源来帮助您,先生?

    谢谢您,致以诚挚的问候。
    Jason Brownlee 2018年5月31日 上午6:16 #

    • 也许一两天。我使用了一些教科书。

      Piyasi Choudhury 2018年6月30日 下午12:16 #

  33. Jason,您做得很好……我想知道我是否可以使用它来概念化一个三向分裂树——一个可以有三个类而不是二元类的树?

    Jason Brownlee 2018年7月1日 上午6:22 #

    • Then 2018年9月24日 下午6:15 #

      我看不出为什么不。

  34. 我该如何实现这个代码用于多类分类?

    你好…
    Jason Brownlee 2018年9月25日 上午6:18 #

  35. 我该如何实现您的代码用于多类分类?

    嗨!
    Jason Brownlee 2018年9月26日 上午6:10 #
    谢谢。

    • 我鼓励您使用 scikit-learn,因为修改此示例以进行多类分类不适合初学者。

      Fraser 2018年10月24日 上午2:50 #

  36. 您可能永远看不到这个,因为它发布这篇文章已经很久了。

    你好 Jason,

    我在 PyCharm 中使用 python 3.6 运行您的代码,我注意到如果我注释掉

    函数,代码就能正常运行,但准确率得分变成了

    def str_column_to_int(dataset, column)

    Scores: [82.92682926829268, 75.60975609756098, 97.5609756097561, 80.48780487804879, 68.29268292682927]

    Trees: 1
    Scores: [56.09756097560976, 63.41463414634146, 60.97560975609756, 58.536585365853654, 73.17073170731707]
    Mean Accuracy: 62.439%
    Trees: 5
    Scores: [70.73170731707317, 58.536585365853654, 85.36585365853658, 75.60975609756098, 63.41463414634146]
    Mean Accuracy: 70.732%
    Trees: 10
    Mean Accuracy: 80.976%
    10 棵树的准确率有所提高。

    Process finished with exit code 0

    有什么想法吗?

    Jason Brownlee 2018年10月24日 上午6:32 #

    • 更多的树对这个问题更好!

      Shipika Singh 2018年10月24日 上午6:12 #

  37. 非常好的解释!但我正在思考,如果我从一个数据集中创建一个随机森林,然后将单个文档传递给它进行测试,该怎么办?将单个文档传递给随机森林的 clf 的方法是什么?

    你好,
    Jason Brownlee 2018年10月24日 上午6:34 #

    • 本教程旨在学习随机森林的工作原理。如果您正在从事项目,我建议您使用 sklearn 的随机森林。

      Elizabeth 2018年10月24日 下午12:22 #

  38. 这是一个很棒的教程。我一直在做一个关于 R 中随机森林项目的研究,并且一直在阅读有关使用此方法的信息。我很困惑,因为一些文章指出 RF 不会过拟合,但似乎在 stackoverflow 上不断讨论 RF 的过拟合问题。RF 模型会过拟合吗?我的第二个问题是关于基尼减少得分——这些是否受到相关变量的影响?(我知道 RF 可以很好地处理相关预测变量)。最后一个问题——如果使用 caret 中的 CV,是否需要 train/test 样本?我有一个非常不平衡的结果分类器,数据量也不多,所以除非绝对必要,否则我不想进一步分割它。

    嗨 Jason,
    Jason Brownlee 2018年10月24日 下午2:46 #
    谢谢!

    • 通常,bagging 树不会过拟合。我读过也观察过,这甚至可能是真的。

      树对相关输入是不变的。

      仅 CV 或 train/test 可能就足够了,可能不需要两者都用。

      amjad 2018年12月16日 下午9:22 #

  39. 我有十个变量,一个因变量和九个自变量,首先我将选取自变量样本,然后是观测样本,最后是预测模型。

    Jason Brownlee 2018年12月17日 上午6:20 #

    • 随机森林将仅使用自变量来选择分割点。

      Julie 2019年1月4日 上午3:23 #

  40. 感谢您出色的工作!

    嗨,Jason,

    我在 Spyder 中使用 python 3.7 运行您的代码,但我遇到了这个错误:

    “left, right = node[‘groups’]
    TypeError: cannot unpack non-iterable NoneType object”。
    我不明白为什么……您有什么想法吗?

    Jason Brownlee 2019年1月4日 上午6:33 #

    谢谢。

  41. 非常感谢您提供的精彩网站和您在此所做的精彩工作。

    Jason博士您好,
    我浏览了您的教程,获得了与教程中相同的准确率。我意识到属性是带放回抽样的,所以我进行了修改,并将交叉熵损失应用于 n_trees = [1, 5, 10, 15, 20]。我获得了以下准确率指标:
    Scores: [68.29268292682927, 63.41463414634146, 65.85365853658537, 73.17073170731707, 75.60975609756098]

    Trees: 1
    Mean Accuracy: 69.268%
    Scores: [73.17073170731707, 82.92682926829268, 70.73170731707317, 70.73170731707317, 75.60975609756098]

    Trees: 5
    Mean Accuracy: 74.634%
    Scores: [80.48780487804879, 75.60975609756098, 65.85365853658537, 75.60975609756098, 87.8048780487805]

    Trees: 10
    Mean Accuracy: 77.073%
    Trees: 15

    Scores: [90.2439024390244, 70.73170731707317, 78.04878048780488, 73.17073170731707, 80.48780487804879]
    Trees: 20
    Mean Accuracy: 78.537%

    Scores: [65.85365853658537, 75.60975609756098, 85.36585365853658, 87.8048780487805, 85.36585365853658]
    Mean Accuracy: 80.000%
    Jason Brownlee 2019年1月16日 上午5:42 #

    • Marcin 2019年1月25日 上午1:48 #

      干得好!

  42. 看起来我之前在错误的帖子下评论了 🙂

    你好 Jason,

    我受到启发,并根据本网站的代码实现了一个 Python 随机森林分类器。我更进一步,决定实现自适应随机森林算法。但我遇到了很多问题。

    我实现了存储示例的窗口。但不幸的是,我无法执行分类。我无法将学习步骤转化为稍微自适应的。我卡住了。
    您能给我一些建议、示例,告诉我如何克服这些问题吗?

    Jason Brownlee 2019年1月25日 上午8:45 #

    • 抱歉,我没有自适应随机森林的示例,我之前没有听说过它。

      Marcin 2019年1月25日 下午11:20 #

      • 这是一种能够从数据流中学习的随机森林。它包含一些概念漂移检测方法。

        不幸的是,这并不是一个常见的话题。
        Jason Brownlee 2019年1月26日 上午6:14 #

        • 有趣。祝您的项目好运!

          Marcin 2019年2月2日 上午1:31 #

  43. 您能解释一下,为什么我每次运行您的脚本都能得到相同的分数吗?

    你好 Jason,

    这意味着我们实际上没有实现随机机制。
    Jason Brownlee 2019年2月2日 上午6:23 #

  44. 非常感谢您提供的如此出色的教程。

    Jason Brownlee 2019年3月16日 上午7:47 #

    • Niladri Saha 2019年9月5日 下午8:34 #

      很高兴它有帮助。

  45. 我需要打印预测的数据集。但在打印时,它只返回类别值。我希望结果为:

    嗨,Jason,

    输入数据集 + 预测类别

    “M”代表我的,“R”代表岩石。

    您能告诉我如何做到这一点吗?

    • Jason Brownlee 2019年9月6日 上午4:56 #

      您可以将预测的整数映射回类别标签并打印类别标签。

      抱歉,我无法为您准备代码示例。

  46. Ravi Kumar 2019年12月9日 下午9:38 #

    如何在 Python 或 R 中实现网络引导森林(Network Guided Forest)

  47. Arkadiy 2020年1月11日 下午9:38 #

    你好,Jason

    据我所知,树应该继续进行分割,直到达到 max_depth 或左侧的观测值完全纯净。但此代码即使在节点已经纯净(gini = 0)时仍进行分割,这意味着它从同一节点创建了两个都具有类别值为零的叶子,这是不可行的。

    为了更清楚:如果您将 number of rows 的值给 get_split(),其中包含相同类别值的行,它仍然会进行分割,尽管它已经纯净了。

    我们是否应该将此条件添加到 get_split() 函数中,或者我是否理解错了什么?

    SKlearn 中的随机森林分类器在同一情况下表现如何?

    提前感谢您的回复。

    诚挚的问候,
    Arkadiy

  48. younes gou 2020年3月20日 上午4:23 #

    Jason 你好,对于随机森林,我们可以将回归问题转换为分类问题吗?

    • Jason Brownlee 2020年3月20日 上午8:48 #

      是的,您可以。我无法为您执行此转换。

  49. Markus 2020年3月24日 上午12:35 #

    给定应用于 cross_validation_split 函数的 208 行的声纳数据集,我们只考虑给定数据集的前 205 行,因此最后 3 行被忽略了。这是故意的吗?

    所以我希望将其更改为类似

    谢谢

    • Markus 2020年3月24日凌晨1:05 #

      您是否知道如何在您的网站上正确添加代码片段?也许可以在常见问题解答中添加一个条目?

    • Jason Brownlee 2020年3月24日凌晨6:03 #

      是的,以保持折叠大小相同。

      • Markus 2020年3月24日凌晨6:19 #

        谢谢你的回复。

        我理解您的理由,但这会以丢失那额外三行提供的信息为代价。这不好吗?

        所有折叠大小都相同的目的是什么?我相应地修改了该函数中的代码,显然得到了与您不同的准确率。

        • Jason Brownlee 2020年3月24日凌晨7:59 #

          也许可以。

          所有折叠大小相同意味着在评估分数样本上计算的汇总统计量是适当独立的同分布。

  50. Markus 2020年3月24日凌晨9:31 #

    以上那行代码的原理是什么?

    train_set = sum(train_set, [])

    如果我这样做,它会有同样的效果吗?

    train_set = train_set[0]

    谢谢

    • Jason Brownlee 2020年3月24日晚上1:42 #

      我认为这一行是多余的。

      • Markus 2020年3月24日晚上6:09 #

        如果我删除那一行,就会出现错误。

        回溯(最近一次调用)
        File “implement-random-forest-scratch-python.py”, line 210, in
        scores = evaluate_algorithm(dataset, random_forest, n_folds, max_depth, min_size, sample_size, n_trees, n_features)
        File “implement-random-forest-scratch-python.py”, line 67, in evaluate_algorithm
        predicted = algorithm(train_set, test_set, *args)
        File “implement-random-forest-scratch-python.py”, line 188, in random_forest
        tree = build_tree(sample, max_depth, min_size, n_features)
        File “implement-random-forest-scratch-python.py”, line 152, in build_tree
        root = get_split(train, n_features)
        File “implement-random-forest-scratch-python.py”, line 105, in get_split
        class_values = list(set(row[-1] for row in dataset))
        TypeError: unhashable type: ‘list’

        我已验证,在该行之前,train_set 列表的维度始终是
        (4, 41, 61)
        在该行之后,它变成
        (164, 61)

        这是 sum 函数的副作用,它将第一个和第二个维度合并为一个,就像在 numpy 中执行类似操作一样:

        > X.shape
        [a, b, c]

        X = X.reshape([a*b, c])

        > X.shape
        [a*b, c]

        • Jason Brownlee 2020年3月25日凌晨6:27 #

          啊,是的,我明白了。我写这篇教程已经很多年了。

  51. Markus 2020年3月25日晚上9:57 #

    根据我的理解,要计算给定特征的基尼指数,首先我们需要迭代所有行,并考虑给定行所对应的该特征的值,然后将条目添加到组中,并一直保留它们,直到我们处理完数据集的所有行。只有这样,我们才能继续计算给定特征的基尼指数。

    然而,查看 get_split 函数,情况似乎并非如此,因为我们在每一步都基于单行计算基尼指数。

    谢谢

  52. SK 2020年4月6日凌晨12:25 #

    先生,
    我尝试了这段代码来处理我的数据集,准确率是 86.6%。
    如何对未标记数据进行预测?
    yhat = model.predict(X)。对于这个语句,应该是‘model’。fit 和 predict 方法显示错误。你能给我一些建议吗?因为我是面向对象概念的初学者。

  53. David Sanchez 2020年4月13日晚上5:52 #

    嗨,Jason,

    我想知道您是否有关于随机森林中非平稳输入方面的帖子。

    我正在做一个关于非平稳数据的项目,我发现当直接使用非平稳数据作为输入时,我的 Scikit-learn 随机森林模型比差分化以实现平稳性的模型具有更高的预测准确率,因此我想看看随机森林如何处理非平稳性。

    附注:我喜欢您的帖子!

    • Jason Brownlee 2020年4月14日凌晨6:06 #

      我可能会,我现在记不清了,抱歉。

      尝试在建模前使数据平稳。

  54. nnvIIT 2020年11月25日凌晨12:08 #

    你好
    感谢这篇精彩的帖子。
    我遇到了一个错误,在使用我的新数据运行时,但在使用您的数据时运行良好。
    错误是
    —————————————————————————
    IndexError Traceback (最近一次调用)
    in
    1 for n_trees in [1,5,10]
    —-> 2 scores = evaluate_algorithm(data, random_forest, n_folds, max_depth, min_size, sample_size,n_trees,n_features)
    3 print(‘Trees: %d’ % n_trees)
    4 print(‘Scores: %s’ % scores)
    5 print(‘Mean accuracy: %.3f%%’ % (sum(scores)/float(len(scores))))

    在 evaluate_algorithm(dataset, algorithm, n_folds, *args)中
    60 test_set.append(row_copy)
    61 row_copy[-1] = None
    —> 62 predicted = algorithm(train_set, test_set, *args)
    63 actual = [row[-1] for row in fold]
    64 accuracy = accuracy_metric(actual, predicted)

    in random_forest(train, test, max_depth, min_size, sample_size, n_trees, n_features)
    181 for i in range(n_trees)
    182 sample = subsample(train, sample_size)
    –> 183 tree = build_tree(sample, max_depth, min_size, n_features)
    184 trees.append(tree)
    185 predictions = [bagging_predict(trees, row) for row in test]

    in build_tree(train, max_depth, min_size, n_features)
    145 # Build a decision tree
    146 def build_tree(train, max_depth, min_size, n_features)
    –> 147 root = get_split(train, n_features)
    148 split(root, max_depth, min_size, n_features, 1)
    149 return root

    in get_split(dataset, n_features)
    102 features = list()
    103 while len(features) 104 index = randrange(len(dataset[0])-1)
    105 if index not in features
    106 features.append(index)

    IndexError: 列表索引超出范围

    任何帮助都将非常有帮助,提前感谢。

  55. Ramya 2021年8月1日凌晨3:10 #

    在 RF 中,随机分割和自定义分割是什么意思?在用于推荐时,能否请您详细说明一下?

    • Jason Brownlee 2021年8月1日凌晨4:51 #

      RF 会选择一个随机的特征子集,然后从中选择最佳分割。这不是随机分割。

留下回复

Machine Learning Mastery 是 Guiding Tech Media 的一部分,Guiding Tech Media 是一家领先的数字媒体出版商,专注于帮助人们了解技术。访问我们的公司网站以了解更多关于我们的使命和团队的信息。