【问题标题】:Get all values of a terminal (leaf) node in a DecisionTreeRegressor获取 DecisionTreeRegressor 中终端(叶)节点的所有值
【发布时间】:2020-12-26 21:26:35
【问题描述】:

决策树会拆分节点,直到出现一些破坏条件,并使用任何节点中值的平均值作为预测。

我想获取这样一个节点中的所有值,而不仅仅是平均值,然后执行更复杂的操作。我正在使用sklearn。我没有找到任何答案,只是一种使用DecisionTreeRegressor.tree_.value获取所有节点平均值的方法。

怎么做?

【问题讨论】:

    标签: python machine-learning scikit-learn decision-tree


    【解决方案1】:

    感谢@desertnaut,我们得到了一个非常好的答案。对于想要基于 pandas 的解决方案的人,我建议使用以下代码:

    import numpy as np
    from sklearn.tree import DecisionTreeRegressor
    import pandas as pd
    
    ## Dummy data code provided by desertnaut
    rng = np.random.RandomState(1)  # for reproducibility
    X = np.sort(5 * rng.rand(80, 1), axis=0)
    y = np.sin(X).ravel()
    y[::5] += 3 * (0.5 - rng.rand(16))
    
    ## Assuming X and y to be pd.DataFrame
    X, y = pd.DataFrame(X, columns=['input']), pd.DataFrame(y, columns=['output'])
    
    ## Train a regression tree
    estimator = DecisionTreeRegressor(max_depth=3)
    estimator.fit(X, y)
    
    leaf_index = pd.DataFrame(estimator.apply(X), columns=['leaf_index'], index=y.index)
    leaf_df = pd.concat([leaf_index, y], axis=1).groupby('leaf_index')\
                                                .apply(lambda x: x['output'].unique())\
                                                .to_frame('leaf_values').reset_index()
    leaf_df['leaf_size'] = leaf_df.leaf_values.apply(len) 
    

    Jupyter 显示以下数据框,如您所见,我们得到的结果与 Desertnaut 的结果相同。

    之后,就很容易得到与给定观测值 x 对应的叶子样本了。

    leaf_df.loc[leaf_index == estimator.apply(x), 'leaf_values']
    

    【讨论】:

      【解决方案2】:

      AFAIK 对此没有任何 API 方法,但您当然可以通过编程方式获取它们。

      让我们先制作一些虚拟数据并构建一个回归树来证明这一点:

      import numpy as np
      from sklearn.tree import DecisionTreeRegressor, export_graphviz
      
      # dummy data
      rng = np.random.RandomState(1)  # for reproducibility
      X = np.sort(5 * rng.rand(80, 1), axis=0)
      y = np.sin(X).ravel()
      y[::5] += 3 * (0.5 - rng.rand(16))
      
      estimator = DecisionTreeRegressor(max_depth=3)
      estimator.fit(X, y)
      
      import graphviz 
      dot_data = export_graphviz(estimator, out_file=None) 
      
      graph = graphviz.Source(dot_data) 
      graph
      

      这是我们的决策树图:

      从中我们可以明显看出我们有 8 个叶子,其中描述了样本的数量和每个叶子的平均值。

      这里的关键命令是apply

      on_leaf = estimator.apply(X)
      on_leaf
      # result:
      array([ 3,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  6,  6,  6,  6,  6,  6,
              6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6,
              6,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
             10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 13, 13, 13,
             13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14])
      

      on_leaf 的长度等于我们的数据X 和结果y;它给出了每个样本结束的节点的索引(on_leaf 中的所有节点都是终端节点,即叶子)。它的唯一值的个数等于我们的叶子的个数,这里是 8:

      len(np.unique(on_leaf))
      # 8
      

      on_leaf[k] 给出了y[k] 结束的节点数。

      现在我们可以得到 8 片叶子中每一片叶子的实际 y 值:

      leaves = []
      for i in np.unique(on_leaf):
        leaves.append(y[np.argwhere(on_leaf==i)]) 
      
      len(leaves)
      # 8
      

      让我们验证一下,按照我们的情节,第一片叶子只有一个样本,其值为-1.149(因为是单样本叶子,所以样本的值等于均值):

      leaves[0]
      # array([[-1.1493464]])
      

      看起来不错。那么第二片叶子呢,有 10 个样本,平均值为-0.173

      leaves[1]
      # result:
      array([[ 0.09131401],
             [ 0.09668352],
             [ 0.13651039],
             [ 0.19403525],
             [-0.12383814],
             [ 0.26365828],
             [ 0.41252216],
             [ 0.44546446],
             [ 0.47215529],
             [-0.26319138]])
      
      len(leaves[1])
      # 10
      
      leaves[1].mean()
      # 0.17253138570808904
      

      以此类推 - 最后检查最后一片叶子(#7),有 4 个样本,平均值为 -0.99

      leaves[7]
      # result:
      array([[-0.99994398],
             [-0.99703245],
             [-0.99170146],
             [-0.9732277 ]])
      
      leaves[7].mean()
      # -0.9904763973694366
      

      总结一下:

      您需要的数据X、结果y 和决策树回归器estimator 是:

      on_leaf = estimator.apply(X)
      
      leaves = []
      for i in np.unique(on_leaf):
        leaves.append(y[np.argwhere(on_leaf==i)]) 
      

      【讨论】:

        猜你喜欢
        • 2019-02-21
        • 2016-11-12
        • 1970-01-01
        • 1970-01-01
        • 2015-10-01
        • 2014-12-11
        • 1970-01-01
        • 2012-05-04
        • 2020-04-10
        相关资源
        最近更新 更多