Comment les feature_importances dans RandomForestClassifier sont-elles déterminées?

125

J'ai une tâche de classification avec une série chronologique comme entrée de données, où chaque attribut (n = 23) représente un moment spécifique. Outre le résultat de la classification absolue, j'aimerais savoir quels attributs / dates contribuent au résultat dans quelle mesure. Par conséquent, j'utilise juste le feature_importances_, qui fonctionne bien pour moi.

Cependant, j'aimerais savoir comment ils sont calculés et quelle mesure / quel algorithme est utilisé. Malheureusement, je n'ai trouvé aucune documentation sur ce sujet.

user2244670
la source
10
Woah trois développeurs de base dans un seul thread SO. Ça doit être une sorte de record ^^
Andreas Mueller

Réponses:

158

Il existe en effet plusieurs manières d'obtenir des "importances" de fonctionnalité. Comme souvent, il n'y a pas de consensus strict sur la signification de ce mot.

Dans scikit-learn, nous implémentons l'importance comme décrit dans [1] (souvent cité, mais malheureusement rarement lu ...). Elle est parfois appelée «importance gini» ou «impureté moyenne de diminution» et est définie comme la diminution totale de l'impureté du nœud (pondérée par la probabilité d'atteindre ce nœud (qui est approximée par la proportion d'échantillons atteignant ce nœud)) moyennée sur tout arbres de l'ensemble.

Dans la littérature ou dans certains autres packages, vous pouvez également trouver des caractéristiques importantes implémentées comme la «précision de diminution moyenne». Fondamentalement, l'idée est de mesurer la diminution de la précision sur les données OOB lorsque vous permutez de manière aléatoire les valeurs de cette fonctionnalité. Si la diminution est faible, la fonction n'est pas importante et vice-versa.

(Notez que les deux algorithmes sont disponibles dans le package randomForest R.)

[1]: Breiman, Friedman, "Arbres de classification et de régression", 1984.

Gilles Louppe
la source
48
Cela pourrait être formidable si cette réponse était mentionnée dans la documentation des attributs / exemple d'importance. Je le cherchais aussi depuis un moment :)
d1337
2
Il semble que le score d'importance soit en valeur relative? Par exemple, la somme des scores d'importance de toutes les fonctionnalités est toujours 1 (voir l'exemple ici scikit-learn.org/stable/auto_examples/ensemble/… )
RNA
5
@RNA: Oui, par défaut, les importances de variables sont normalisées dans scikit-learn, de sorte qu'elles totalisent un. Vous pouvez contourner cela en effectuant une boucle sur les estimateurs de base individuels et en appelant tree_.compute_feature_importances(normalize=False).
Gilles Louppe
2
@GillesLouppe Utilisez-vous les échantillons hors sac pour mesurer la réduction de la MSE pour une forêt de régresseurs d'arbre de décision dans chaque arbre? Ou toutes les données d'entraînement utilisées sur l'arbre?
Cokes
1
Deux ressources utiles. (1) blog.datadive.net/... un blog d'Ando Saabas met en œuvre à la fois "diminution moyenne de l'impureté" et aussi "diminution moyenne de la précision" comme le mentionne Gilles. (2) Téléchargez et lisez la thèse de Gilles Louppe.
Mark Teese
54

La façon habituelle de calculer les valeurs d'importance des caractéristiques d'un seul arbre est la suivante:

  1. vous initialisez un tableau feature_importancesde tous les zéros avec la taille n_features.

  2. vous parcourez l'arborescence: pour chaque nœud interne qui se divise sur l'entité, ivous calculez la réduction d'erreur de ce nœud multipliée par le nombre d'échantillons qui ont été acheminés vers le nœud et ajoutez cette quantité feature_importances[i].

La réduction des erreurs dépend du critère d'impureté que vous utilisez (par exemple Gini, Entropy, MSE, ...). C'est l'impureté de l'ensemble d'exemples qui est acheminée vers le nœud interne moins la somme des impuretés des deux partitions créées par la scission.

Il est important que ces valeurs soient relatives à un ensemble de données spécifique (la réduction des erreurs et le nombre d'échantillons sont spécifiques à l'ensemble de données), de sorte que ces valeurs ne peuvent pas être comparées entre différents ensembles de données.

Autant que je sache, il existe d'autres moyens de calculer les valeurs d'importance des caractéristiques dans les arbres de décision. Une brève description de la méthode ci-dessus peut être trouvée dans "Elements of Statistical Learning" par Trevor Hastie, Robert Tibshirani et Jerome Friedman.

Peter Prettenhofer
la source
12

C'est le rapport entre le nombre d'échantillons acheminés vers un nœud de décision impliquant cette caractéristique dans l'un des arbres de l'ensemble sur le nombre total d'échantillons dans l'ensemble d'apprentissage.

Les fonctionnalités impliquées dans les nœuds de niveau supérieur des arbres de décision ont tendance à voir plus d'échantillons et sont donc susceptibles d'avoir plus d'importance.

Edit : cette description n'est que partiellement correcte: les réponses de Gilles et Peter sont la bonne réponse.

ogrisel
la source
1
Savez-vous s'il existe du papier / de la documentation sur la méthode exacte? par exemple. Breiman, 2001. Ce serait formidable si j'avais un document approprié, que je pourrais citer pour la méthodologie.
user2244670
@ogrisel, ce serait formidable si vous pouviez clairement marquer votre réponse comme l'explication de la "pondération". La pondération seule ne détermine pas l'importance de la fonctionnalité. La "métrique d'impureté" ("gini-importance" ou RSS) combinée aux poids, moyennée sur les arbres, détermine l'importance globale de la caractéristique. Malheureusement, la documentation sur scikit-learn ici: scikit-learn.org/stable/modules/… n'est pas précise et mentionne à tort la "profondeur" comme métrique d'impureté.
Ariel
11

Comme @GillesLouppe l'a souligné ci-dessus, scikit-learn implémente actuellement la métrique «diminution moyenne d'impureté» pour les importances de fonctionnalités. Personnellement, je trouve la deuxième métrique un peu plus intéressante, où vous permutez au hasard les valeurs de chacune de vos fonctionnalités une par une et voyez à quel point vos performances hors du sac sont bien pires.

Étant donné que ce que vous recherchez avec l'importance des fonctionnalités, c'est la contribution de chaque fonctionnalité aux performances prédictives de votre modèle global, la deuxième métrique vous en donne une mesure directe, tandis que la "diminution moyenne de l'impureté" n'est qu'un bon proxy.

Si vous êtes intéressé, j'ai écrit un petit package qui implémente la métrique Importance de la permutation et peut être utilisé pour calculer les valeurs à partir d'une instance d'une classe de forêt aléatoire scikit-learn:

https://github.com/pjh2011/rf_perm_feat_import

Edit: Cela fonctionne pour Python 2.7, pas 3

Peter
la source
Salut @Peter lorsque j'utilise votre code, j'obtiens cette erreur: NameError: le nom 'xrange' n'est pas défini.
Aizzaac
Salut @Aizzaac. Désolé, je suis nouveau dans l'écriture de packages, alors j'aurais dû noter que je l'ai écrit pour Python 2.7. Essayez def xrange (x): retournez iter (range (x)) avant de l'exécuter
Peter
2

Laissez-moi essayer de répondre à la question. code:

iris = datasets.load_iris()  
X = iris.data  
y = iris.target  
clf = DecisionTreeClassifier()  
clf.fit(X, y)  

décision_tree plot:
entrez la description de l'image ici
Nous pouvons obtenir compute_feature_importance: [0. , 0.01333333,0.06405596,0.92261071]
Vérifiez le code source:

cpdef compute_feature_importances(self, normalize=True):
    """Computes the importance of each feature (aka variable)."""
    cdef Node* left
    cdef Node* right
    cdef Node* nodes = self.nodes
    cdef Node* node = nodes
    cdef Node* end_node = node + self.node_count

    cdef double normalizer = 0.

    cdef np.ndarray[np.float64_t, ndim=1] importances
    importances = np.zeros((self.n_features,))
    cdef DOUBLE_t* importance_data = <DOUBLE_t*>importances.data

    with nogil:
        while node != end_node:
            if node.left_child != _TREE_LEAF:
                # ... and node.right_child != _TREE_LEAF:
                left = &nodes[node.left_child]
                right = &nodes[node.right_child]

                importance_data[node.feature] += (
                    node.weighted_n_node_samples * node.impurity -
                    left.weighted_n_node_samples * left.impurity -
                    right.weighted_n_node_samples * right.impurity)
            node += 1

    importances /= nodes[0].weighted_n_node_samples

    if normalize:
        normalizer = np.sum(importances)

        if normalizer > 0.0:
            # Avoid dividing by zero (e.g., when root is pure)
            importances /= normalizer

    return importances

Essayez de calculer l'importance de la fonctionnalité:

print("sepal length (cm)",0)
print("sepal width (cm)",(3*0.444-(0+0)))
print("petal length (cm)",(54* 0.168 - (48*0.041+6*0.444)) +(46*0.043 -(0+3*0.444)) + (3*0.444-(0+0)))
print("petal width (cm)",(150* 0.667 - (0+100*0.5)) +(100*0.5-(54*0.168+46*0.043))+(6*0.444 -(0+3*0.444)) + (48*0.041-(0+0)))

Nous obtenons feature_importance: np.array ([0,1.332,6.418,92.30]).
Après normalisé, nous pouvons obtenir un tableau ([0., 0.01331334, 0.06414793, 0.92253873]), c'est la même chose que clf.feature_importances_.
Attention, toutes les classes sont censées avoir un poids un.

tengfei li
la source
1

Pour ceux qui recherchent une référence à la documentation de scikit-learn sur ce sujet ou une référence à la réponse de @GillesLouppe:

Dans RandomForestClassifier, l' estimators_attribut est une liste de DecisionTreeClassifier (comme mentionné dans la documentation ). Afin de calculer le feature_importances_pour RandomForestClassifier, dans le code source de scikit-learn , il fait la moyenne de tous les feature_importances_attributs de l' estimateur (tous ceux de DecisionTreeClassifer) dans l'ensemble.

Dans la documentation de DecisionTreeClassifer , il est mentionné que "L'importance d'une fonctionnalité est calculée comme la réduction totale (normalisée) du critère apporté par cette fonctionnalité. Elle est également connue sous le nom d'importance de Gini [1]."

Voici un lien direct pour plus d'informations sur les variables et l'importance de Gini, comme fourni par la référence de scikit-learn ci-dessous.

[1] L. Breiman et A. Cutler, «Random Forests», http://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm

Makan
la source