【问题标题】:What does "splitter" attribute in sklearn's DecisionTreeClassifier do?sklearn 的 DecisionTreeClassifier 中的“拆分器”属性有什么作用?
【发布时间】:2018-03-27 03:58:18
【问题描述】:

sklearn DecisionTreeClassifier 有一个属性叫“splitter”,默认设置为“best”,设置为“best”或“random”有什么作用?我无法从官方文档中找到足够的信息。

【问题讨论】:

    标签: python python-3.x machine-learning scikit-learn


    【解决方案1】:

    其实,“random”参数是用来在sklearn中实现额外的随机化树的。简而言之,这个参数意味着分裂算法会遍历所有特征,只是随机选择最大特征值和最小特征值之间的分裂点。如果你对算法的细节感兴趣,可以参考这篇论文[1]。此外,如果您对该算法的详细实现感兴趣,请you can refer to this page

    [1]。 P. Geurts、D. Ernst. 和 L. Wehenkel,“极端随机树”,机器学习,63(1),3-42,2006。

    【讨论】:

      【解决方案2】:

      有两件事需要考虑,criterionsplitter。在所有的解释中,我将使用 wine 数据集示例:

      标准:

      用于评估特征重要性。默认值为gini,但您也可以使用entropy。在此基础上,模型将定义每个特征对分类的重要性。

      示例

      使用“gini”标准的葡萄酒数据集的特征重要性为:

                                   alcohol -> 0.04727507393151268
                                malic_acid -> 0.0
                                       ash -> 0.0
                         alcalinity_of_ash -> 0.0
                                 magnesium -> 0.0329784450464887
                             total_phenols -> 0.0
                                flavanoids -> 0.1414466773122087
                      nonflavanoid_phenols -> 0.0
                           proanthocyanins -> 0.0
                           color_intensity -> 0.0
                                       hue -> 0.08378677906228588
              od280/od315_of_diluted_wines -> 0.3120425747831769
                                   proline -> 0.38247044986432716
      

      使用“熵”标准的葡萄酒数据集的特征重要性为:

                                   alcohol -> 0.014123729330936566
                                malic_acid -> 0.0
                                       ash -> 0.0
                         alcalinity_of_ash -> 0.02525179137252771
                                 magnesium -> 0.0
                             total_phenols -> 0.0
                                flavanoids -> 0.4128453371544815
                      nonflavanoid_phenols -> 0.0
                           proanthocyanins -> 0.0
                           color_intensity -> 0.22278576133186542
                                       hue -> 0.011635633063349873
              od280/od315_of_diluted_wines -> 0.0
                                   proline -> 0.31335774774683883
      

      结果因random_state 而异,所以我认为只有数据集的一个子集用于计算它。

      分离器:

      分割器用于决定使用哪个特征和哪个阈值。

      • 使用best,模型如果采用最重要的特征
      • 使用random,模型如果随机抽取特征但分布相同(在giniproline 的重要性为 38%,因此将在 38% 的情况下抽取)

      例子:

      在使用criterion="gini", splitter="best" 训练 1000 个DecisionTreeClassifier 之后,这是第一次拆分时使用的“特征数”和“阈值”的分布

      它总是选择特征 12 (=proline),threshold 为 755。这是训练模型之一的头部:

      splitter= "random"做同样的事情,结果是:

      由于使用了不同的特征,阈值变化更大,这里是过滤模型以特征 12 作为第一个分割的结果:

      我们可以看到模型也在随机地对threshold进行拆分。通过查看特征 12 在类别方面的分布,我们有:

      红线是splitter="best" 时使用的threshold。 现在,使用随机,模型将随机选择一个threshold 值(我认为正态分布,具有特征的均值/标准差,但我不确定)引导以绿灯为中心的分布,最小最大值为蓝色(使用 1353 个随机训练的模型完成,具有特征 12 进行拆分)

      重现代码:

      from sklearn import datasets
      from sklearn.tree import DecisionTreeClassifier, plot_tree, _tree
      import numpy as np
      import matplotlib.pyplot as plt
      
      wine = datasets.load_wine()
      
      # Feature importance
      
      clf = DecisionTreeClassifier(criterion="gini", splitter='best', random_state=42)
      clf = clf.fit(wine.data, wine.target)
      
      for name, val in zip(wine.feature_names, clf.feature_importances_):
          print(f"{name:>40} -> {val}")
      
      print("")
      clf = DecisionTreeClassifier(criterion="entropy", splitter='best', random_state=42)
      clf = clf.fit(wine.data, wine.target)
      
      for name, val in zip(wine.feature_names, clf.feature_importances_):
          print(f"{name:>40} -> {val}")
      
      # Feature selected first and threshold
      
      features = []
      tresholds = []
      for random in range(1000):
          clf = DecisionTreeClassifier(criterion="gini", splitter='best', random_state=random)
          clf = clf.fit(wine.data, wine.target)
          features.append(clf.tree_.feature[0])
          tresholds.append(clf.tree_.threshold[0])
      
      # plot distribution
      fig, (ax, ax2) = plt.subplots(1, 2, figsize=(20, 5))
      ax.hist(features, bins=np.arange(14)-0.5)
      ax2.hist(tresholds)
      ax.set_title("Number of the first used for split")
      ax2.set_title("Value of the threshold")
      plt.show()
      
      # plot model
      plt.figure(figsize=(20, 12))
      plot_tree(clf) 
      plt.show()
      
      # plot filtered result
      threshold_filtered = [val for feat, val in zip(features, tresholds) if feat==12]
      fig, ax = plt.subplots(1, 1, figsize=(20, 10))
      ax.hist(threshold_filtered)
      ax.set_title("Number of the first used for split")
      plt.show()
      
      feature_number = 12
      X1, X2, X3 = wine.data[wine.target==0][:, feature_number], wine.data[wine.target==1][:, feature_number], wine.data[wine.target==2][:, feature_number]
      
      fig, ax = plt.subplots()
      ax.set_title(f'feature {feature_number} - distribution')
      ax.boxplot([X1, X2, X3])
      ax.hlines(755, 0.5, 3.5, colors="r", linestyles="dashed")
      ax.hlines(min(threshold_filtered), 0.5, 3.5, colors="b", linestyles="dashed")
      ax.hlines(max(threshold_filtered), 0.5, 3.5, colors="b", linestyles="dashed")
      ax.hlines(sum(threshold_filtered)/len(threshold_filtered), 0.5, 3.5, colors="g", linestyles="dashed")
      plt.xlabel("Class")
      plt.show()
      

      【讨论】:

      • 那么如果我选择“随机”,基尼杂质或信息增益不会计算?因为计算它们并使用“随机”没有任何意义,对吗?
      • 我猜它会在之后计算,但不会用于选择最佳特征。
      • 这个答案似乎是错误的。随机分离器遍历所有特征。对于每一项功能,它仅在该功能的最小值和最大值之间的一个随机分割处进行测试。
      • 你说得对,我可能混淆了标准和拆分器。我将在本周末调查并编辑答案。
      • @John,我已经完全重新开始解释,提供更多细节,我希望现在更清楚,错误更少(我唯一不明白的一点是 threshold 的值是多少在random 中选择。一些近似值是由于缺乏知识(我在开始数据科学后不到一年就写了这个答案)
      【解决方案3】:

      简短的回答:

      RandomSplitter 会在每个选定的特征上启动**随机拆分**,而 BestSplitter 会进行**在每个选定特征上的所有可能拆分**。


      更长的解释:

      当您通过 _splitter.pyx 时,这一点很清楚。

    • RandomSplitter 仅计算随机启动的阈值的改进(参考第 761 和 801 行)。 BestSplitter 在一个 while 循环中遍历所有可能的拆分(参考第 436 行(循环开始的地方)和 462 行)。 [注意:行与版本 0.21.2 相关。]
    • 与 2017 年 10 月 15 日和 2018 年 2 月 1 日的早期响应不同,RandomSplitter 和 BestSplitter 都循环遍历所有相关功能。这在 _splitter.pyx 中也很明显。
    • 【讨论】:

        【解决方案4】:

        “随机”设置随机选择一个特征,然后随机拆分它并计算基尼。它会重复多次,比较所有的分裂,然后选择最好的一个。

        这有几个优点:

        1. 与计算每个叶子的每个特征的最佳分割相比,它的计算强度更低。
        2. 它应该不太容易过度拟合。
        3. 如果您的决策树是集成方法的一个组成部分,则额外的随机性很有用。

        【讨论】:

        • 这似乎是错误的。随机分离器遍历所有特征。对于每一项功能,它仅在该功能的最小值和最大值之间的一个随机分割处进行测试。
        猜你喜欢
        • 2016-03-27
        • 2018-11-25
        • 2013-11-19
        • 2020-09-08
        • 1970-01-01
        • 2023-02-20
        • 2018-01-21
        • 2020-05-23
        • 2017-12-20
        相关资源
        最近更新 更多