web-dev-qa-db-fra.com

scikit learn - calcul de l'importance des fonctionnalités dans les arbres de décision

J'essaie de comprendre comment l'importance des fonctionnalités est calculée pour les arbres de décision dans sci-kit learn. Cette question a déjà été posée, mais je ne peux pas reproduire les résultats fournis par l'algorithme.

Par exemple:

from StringIO import StringIO

from sklearn.datasets import load_iris
from sklearn.tree import DecisionTreeClassifier
from sklearn.tree.export import export_graphviz
from sklearn.feature_selection import mutual_info_classif

X = [[1,0,0], [0,0,0], [0,0,1], [0,1,0]]

y = [1,0,1,1]

clf = DecisionTreeClassifier()
clf.fit(X, y)

feat_importance = clf.tree_.compute_feature_importances(normalize=False)
print("feat importance = " + str(feat_importance))

out = StringIO()
out = export_graphviz(clf, out_file='test/tree.dot')

résultats en importance de fonctionnalité:

feat importance = [0.25       0.08333333 0.04166667]

et donne l'arbre de décision suivant:

decision tree

Maintenant, cette réponse à une question similaire suggère que l'importance est calculée comme

formula_a

Où G est l'impureté du nœud, dans ce cas l'impureté gini. C'est la réduction des impuretés pour autant que je l'ai comprise. Cependant, pour la fonctionnalité 1, cela devrait être:

formula_b

Cette réponse suggère que l'importance est pondérée par la probabilité d'atteindre le nœud (qui est approximée par la proportion d'échantillons atteignant ce nœud). Encore une fois, pour la fonctionnalité 1, cela devrait être:

formula_c

Les deux formules fournissent le mauvais résultat. Comment l'importance des fonctionnalités est-elle calculée correctement?

11
Characeae

Je pense que l'importance des fonctionnalités dépend de l'implémentation, nous devons donc consulter la documentation de scikit-learn.

Les fonctionnalités importances. Plus la fonction est élevée, plus elle est importante. L'importance d'une caractéristique est calculée comme la réduction totale (normalisée) du critère apporté par cette caractéristique. Il est également connu comme l'importance Gini

Cette réduction ou gain d'information pondéré est défini comme suit:

L'équation de diminution d'impureté pondérée est la suivante:

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

où N est le nombre total d'échantillons, N_t est le nombre d'échantillons au nœud actuel, N_t_L est le nombre d'échantillons dans l'enfant de gauche et N_t_R est le nombre d'échantillons dans l'enfant de droite.

http://scikit-learn.org/stable/modules/generated/sklearn.tree.DecisionTreeClassifier.html#sklearn.tree.DecisionTreeClassifier

Étant donné que chaque fonctionnalité est utilisée une fois dans votre cas, les informations de fonctionnalité doivent être égales à l'équation ci-dessus.

Pour X [2]:

feature_importance = (4 / 4) * (0.375 - (0.75 * 0.444)) = 0.042

Pour X [1]:

feature_importance = (3 / 4) * (0.444 - (2/3 * 0.5)) = 0.083

Pour X [0]:

feature_importance = (2 / 4) * (0.5) = 0.25

15
Seljuk Gülcan

Une seule caractéristique peut être utilisée dans les différentes branches de l'arbre, son importance est alors sa contribution totale à la réduction de l'impureté.

feature_importance += number_of_samples_at_parent_where_feature_is_used\*impurity_at_parent-left_child_samples\*impurity_left-right_child_samples\*impurity_right

l'impureté est la valeur de gini/entropie

normalized_importance = feature_importance/number_of_samples_root_node(total num of samples)

Dans ce qui précède, par exemple:

feature_2_importance = 0.375*4-0.444*3-0*1 = 0.16799 , 
normalized = 0.16799/4(total_num_of_samples) = 0.04199

Si feature_2 A été utilisé dans d'autres branches, calculez son importance à chacun de ces nœuds parents et résumez les valeurs.

Il y a une différence dans l'importance des fonctionnalités calculées et celles renvoyées par la bibliothèque car nous utilisons les valeurs tronquées vues dans le graphique.

Au lieu de cela, nous pouvons accéder à toutes les données requises en utilisant l'attribut 'tree_' du classificateur qui peut être utilisé pour sonder les caractéristiques utilisées, la valeur seuil, l'impureté, le nombre d'échantillons à chaque nœud, etc.

par exemple: clf.tree_.feature donne la liste des fonctionnalités utilisées. Une valeur négative indique qu'il s'agit d'un nœud feuille.

De même, clf.tree_.children_left/right Donne l'index du clf.tree_.feature Pour les enfants de gauche et de droite

En utilisant ce qui précède, parcourez l'arbre et utilisez les mêmes indices dans clf.tree_.impurity & clf.tree_.weighted_n_node_samples Pour obtenir la valeur gini/entropie et le nombre d'échantillons à chaque nœud et à ses enfants.

def dt_feature_importance(model,normalize=True):

    left_c = model.tree_.children_left
    right_c = model.tree_.children_right

    impurity = model.tree_.impurity    
    node_samples = model.tree_.weighted_n_node_samples 

    # Initialize the feature importance, those not used remain zero
    feature_importance = np.zeros((model.tree_.n_features,))

    for idx,node in enumerate(model.tree_.feature):
        if node >= 0:
            # Accumulate the feature importance over all the nodes where it's used
            feature_importance[node]+=impurity[idx]*node_samples[idx]- \
                                   impurity[left_c[idx]]*node_samples[left_c[idx]]-\
                                   impurity[right_c[idx]]*node_samples[right_c[idx]]

    # Number of samples at the root node
    feature_importance/=node_samples[0]

    if normalize:
        normalizer = feature_importance.sum()
        if normalizer > 0:
            feature_importance/=normalizer

    return feature_importance

Cette fonction renverra exactement les mêmes valeurs que celles renvoyées par clf.tree_.compute_feature_importances(normalize=...)

Pour trier les fonctionnalités en fonction de leur importance

features = clf.tree_.feature[clf.tree_.feature>=0] # Feature number should not be negative, indicates a leaf node
sorted(Zip(features,dt_feature_importance(clf,False)[features]),key=lambda x:x[1],reverse=True)
2
bhasuru