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:
Maintenant, cette réponse à une question similaire suggère que l'importance est calculée comme
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:
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:
Les deux formules fournissent le mauvais résultat. Comment l'importance des fonctionnalités est-elle calculée correctement?
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.
É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
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)