Деревья для обрезки деревьев

Привет, ребята, ниже приведен фрагмент дерева решений, так как оно довольно большое.

enter image description here

Как сделать так, чтобы дерево перестало расти, когда самое низкое значение в узле меньше 5. Вот код для создания дерева решений. В SciKit - Дереве решений мы видим единственный способ сделать это - min_impurity_decrease, но я не уверен, как это конкретно работает.

import numpy as np
import pandas as pd
from sklearn.datasets import make_classification
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier


X, y = make_classification(n_samples=1000,
                           n_features=6,
                           n_informative=3,
                           n_classes=2,
                           random_state=0,
                           shuffle=False)

# Creating a dataFrame
df = pd.DataFrame({'Feature 1':X[:,0],
                                  'Feature 2':X[:,1],
                                  'Feature 3':X[:,2],
                                  'Feature 4':X[:,3],
                                  'Feature 5':X[:,4],
                                  'Feature 6':X[:,5],
                                  'Class':y})


y_train = df['Class']
X_train = df.drop('Class',axis = 1)

dt = DecisionTreeClassifier( random_state=42)                
dt.fit(X_train, y_train)

from IPython.display import display, Image
import pydotplus
from sklearn import tree
from sklearn.tree import _tree
from sklearn import tree
import collections
import drawtree
import os  

os.environ["PATH"] += os.pathsep + 'C:\\Anaconda3\\Library\\bin\\graphviz'

dot_data = tree.export_graphviz(dt, out_file = 'thisIsTheImagetree.dot',
                                 feature_names=X_train.columns, filled   = True
                                    , rounded  = True
                                    , special_characters = True)

graph = pydotplus.graph_from_dot_file('thisIsTheImagetree.dot')  

thisIsTheImage = Image(graph.create_png())
display(thisIsTheImage)
#print(dt.tree_.feature)

from subprocess import check_call
check_call(['dot','-Tpng','thisIsTheImagetree.dot','-o','thisIsTheImagetree.png'])

Обновление

Я думаю, что min_impurity_decrease может помочь достичь цели. Поскольку настройка min_impurity_decrease действительно обрезает дерево. Может кто-нибудь любезно объяснить min_impurity_decrease.

Я пытаюсь понять уравнение в scikit learn, но я не уверен, каково значение right_impurity и left_impurity.

N = 256
N_t = 256
impurity = ??
N_t_R = 242
N_t_L = 14
right_impurity = ??
left_impurity = ??

New_Value = N_t / N * (impurity - ((N_t_R / N_t) * right_impurity)
                    - ((N_t_L / N_t) * left_impurity))
New_Value

Обновление 2

Вместо того, чтобы обрезать по определенному значению, мы обрезаем при определенных условиях. такие как Мы делим на 6/4 и 5/5, но не на 6000/4 или 5000/5. Допустим, что одно значение меньше определенного процента по сравнению с соседним значением в узле, а не определенным значением.

      11/9
   /       \
  6/4       5/5
 /   \     /   \
6/0  0/4  2/2  3/3

Ответы

Ответ 1

Прямое ограничение наименьшего значения (количество вхождений определенного класса) листа не может быть выполнено с помощью min_impurity_decrease или любых других встроенных критериев остановки.

Я думаю, что единственный способ, которым Вы можете сделать это без изменения исходного кода scikit-научиться это пост-подрезать свое дерево. Для этого вы можете просто пересечь дерево и удалить всех дочерних узлов узлов с минимальным количеством классов меньше 5 (или любым другим условием, о котором вы можете думать). Я продолжу ваш пример:

from sklearn.tree._tree import TREE_LEAF

def prune_index(inner_tree, index, threshold):
    if inner_tree.value[index].min() < threshold:
        # turn node into a leaf by "unlinking" its children
        inner_tree.children_left[index] = TREE_LEAF
        inner_tree.children_right[index] = TREE_LEAF
    # if there are shildren, visit them as well
    if inner_tree.children_left[index] != TREE_LEAF:
        prune_index(inner_tree, inner_tree.children_left[index], threshold)
        prune_index(inner_tree, inner_tree.children_right[index], threshold)

print(sum(dt.tree_.children_left < 0))
# start pruning from the root
prune_index(dt.tree_, 0, 5)
sum(dt.tree_.children_left < 0)

этот код будет печатать сначала 74, а затем 91. Это означает, что код создал 17 новых листовых узлов (практически удалив ссылки на своих предков). Дерево, которое раньше казалось

enter image description here

теперь выглядит

enter image description here

так что вы можете видеть, что это действительно уменьшилось.

Ответ 2

Изменить: это неверно, поскольку @SBylemans и @Viktor указывают в комментариях. Я не удаляю ответ, так как кто-то еще может подумать, что это решение.

Установите min_samples_leaf на 5.

min_samples_leaf:

Минимальное количество образцов, которые должны быть у листового узла:

Обновление: я думаю, что это невозможно сделать с помощью min_impurity_decrease. Подумайте о следующем сценарии:

      11/9
   /         \
  6/4       5/5
 /   \     /   \
6/0  0/4  2/2  3/3

Согласно вашему правилу, вы не хотите разделять узел 6/4 поскольку 4 меньше 5, но вы хотите разделить узел 5/5. Тем не менее, разделение 6/4 узла имеет 0,48 информации, а разделение 5/5 имеет 0 усиления информации.

Ответ 3

Интересно, что min_impurity_decrease не выглядит так, как если бы он позволял min_impurity_decrease любой из узлов, которые вы min_impurity_decrease в предоставленном фрагменте (сумма примесей после расщепления равна предварительно раздробленной примеси, поэтому нет никакого уменьшения примесей). Однако, хотя он не даст вам точно результат, который вы хотите (завершите узел, если минимальное значение меньше 5), он может дать вам что-то подобное.

Если мое тестирование правильное, официальные документы делают его более сложным, чем на самом деле. Просто возьмите меньшее значение от потенциального родительского узла, а затем вычтите сумму нижних значений предлагаемых новых узлов - это валовое сокращение примесей. Затем разделите на общее количество выборок во всем дереве - это дает вам уменьшение доли долей, достигнутое, если узел разделен.

Если у вас 1000 образцов и узел с более низким значением 5 (например, 5 "примесей"), 5/1000 представляет максимальное уменьшение примеси, которое вы могли бы достичь, если бы этот узел был идеально разделен. Таким образом, установка min_impurity_decrease 0,005 будет приближать остановку листа с помощью <5 примесей. Это фактически остановило бы большинство листьев с более чем 5 примесями (в зависимости от примесей, возникающих в результате предлагаемого раскола), поэтому это всего лишь приближение, но насколько я могу сказать, что это самое близкое, что вы можете получить без пост-обрезки.

Ответ 4

Мой ответ на ответ "Дэвид Дейл" удален, я должен сказать, что метод, предложенный "Дэвид Дейл" не является идеальным, потому что следующий параметр модели sklearn не будет изменяться синхронно после сокращения:

'

model.tree_.impurity,
model.tree_.value,
model.tree_.children_left,
model.tree_.children_right

и когда вы хотите выполнить алгоритм CCP (сокращение затрат) в модели sklearn CART,

Вы не можете реализовать алгоритм с помощью вышеуказанного метода.

дополнение: мне удалось реализовать сокращение сложности затрат на модели Sklearn, и вот ссылка: https://github.com/appleyuchi/Decision_Tree_Prune