web-dev-qa-db-fra.com

Arbres de décision d'élagage

Salut les gars ci-dessous est un extrait de l'arbre de décision car il est assez énorme.

 enter image description here

Comment faire en sorte que l'arbre cesse de croître lorsque la valeur valeur la plus basse d'un nœud est inférieure à 5. Voici le code permettant de générer l'arbre de décision. Sur SciKit - Decission Tree nous pouvons voir que la seule façon de le faire est de min_impurity_decrease mais je ne suis pas sûr de savoir comment cela fonctionne spécifiquement.

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

Mettre à jour

Je pense que min_impurity_decrease peut en quelque sorte aider à atteindre l'objectif. Comme tordre min_impurity_decrease fait réellement élaguer l’arbre. Quelqu'un peut-il bien vouloir expliquer min_impurity_decrease. 

J'essaie de comprendre l'équation dans scikit learn mais je ne suis pas sûr de la valeur de right_impurity et de 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

Mise à jour 2

Au lieu de tailler à une certaine valeur, nous coupons sous une certaine condition ... telle que Nous nous séparons à 6/4 et à 5/5 mais pas à 6000/4 ni à 5000/5. Supposons qu'une valeur soit inférieure à un certain pourcentage par rapport à sa valeur adjacente dans le nœud, plutôt qu'à une certaine valeur.

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

La restriction directe de la valeur la plus basse (nombre d'occurrences d'une classe particulière) d'une feuille ne peut pas être effectuée avec min_impurity_decrease ou tout autre critère d'arrêt intégré. 

Je pense que la seule façon de réaliser cela sans changer le code source de scikit-learn est de post-Prune votre arbre. Pour ce faire, il vous suffit de parcourir l’arborescence et de supprimer tous les enfants des nœuds dont le nombre de classes minimal est inférieur à 5 (ou toute autre condition que vous puissiez imaginer). Je vais continuer votre exemple:

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)

ce code sera imprimé en premier 74, puis 91. Cela signifie que le code a créé 17 nouveaux nœuds feuilles (en supprimant pratiquement les liens avec leurs ancêtres). L'arbre qui ressemblait auparavant à 

 enter image description here

ressemble maintenant

 enter image description here

vous pouvez donc voir que cela a en effet beaucoup diminué. 

15
David Dale

Edit: Ceci n'est pas correct, comme le signalent @SBylemans et @Viktor dans les commentaires. Je ne supprime pas la réponse car quelqu'un d'autre peut aussi penser que c'est la solution.

Définissez min_samples_leaf sur 5.

min_samples_leaf

Le nombre minimum d'échantillons requis pour être sur un nœud feuille:

Mise à jour: Je pense que cela ne peut pas être fait avec min_impurity_decrease. Pensez au scénario suivant: 

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

Selon votre règle, vous ne souhaitez pas scinder le noeud 6/4 car 4 est inférieur à 5, mais vous souhaitez scinder le 5/5. Toutefois, la scission 6/4 a 0,48 gain d'information et la scission 5/5 a 0 gain d'information.

1
Seljuk Gülcan

Ma réponse à la réponse de "David Dale" est supprimée, Je dois dire que, La méthode proposée par "David Dale" n'est pas parfaite, car le paramètre suivant du modèle sklearn ne sera pas modifié de manière synchrone. après avoir été élagué:

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

` et lorsque vous souhaitez exécuter l'algorithme CCP (élimination de la complexité des coûts) sur le modèle CART de type sklearn,

vous ne pouvez PAS implémenter l'algorithme avec la méthode ci-dessus.

supplément: J'ai réussi à implémenter la taille de la complexité des coûts sur le modèle de Sklearn, et voici le lien: https://github.com/appleyuchi/Decision_Tree_Prune

0
appleyuchi

Il est intéressant de noter que min_impurity_decrease ne semble pas permettre la croissance des nœuds que vous avez indiqués dans l'extrait de code que vous avez fourni (la somme des impuretés après division est égale à l'impureté prédéfinie, il n'y a donc pas de diminution de impuretés ). Cependant, s'il ne vous donne pas exactement le résultat souhaité (noeud terminal si la valeur la plus basse est inférieure à 5), il peut vous donner quelque chose de similaire. 

Si mes tests sont corrects, les documents officiels le rendent plus compliqué qu'il ne l'est réellement. Il suffit de prendre la valeur la plus basse du nœud parent potentiel, puis de soustraire la somme des valeurs les plus basses des nouveaux nœuds proposés - il s'agit de la réduction de l'impureté brute. Puis divisez par le nombre total d'échantillons dans l'arborescence entier - ceci vous donne la diminution d'impuretés fractionnaires obtenue si le nœud est fractionné. 

Si vous avez 1 000 échantillons et un nœud avec une valeur inférieure de 5 (c'est-à-dire 5 "impuretés"), 5/1000 représente la diminution maximale d'impuretés que vous pourriez obtenir si ce nœud était parfaitement divisé. Donc, définir un min_impurity_decrease de 0,005 équivaudrait à arrêter la feuille avec moins de 5 impuretés. En fait, cela arrêterait la plupart des feuilles avec un peu plus de 5 impuretés (en fonction des impuretés résultant de la scission proposée). Ce n'est donc qu'une approximation, mais mieux je peux en dire le plus près possible sans post-élagage.

0
James