Como são determinadas as feature_importances no RandomForestClassifier?

125

Eu tenho uma tarefa de classificação com uma série temporal como entrada de dados, em que cada atributo (n = 23) representa um ponto específico no tempo. Além do resultado absoluto da classificação, gostaria de descobrir quais atributos / datas contribuem para o resultado em que extensão. Portanto, estou apenas usando o feature_importances_, que funciona bem para mim.

No entanto, gostaria de saber como eles estão sendo calculados e qual medida / algoritmo é usado. Infelizmente não consegui encontrar nenhuma documentação sobre este tópico.

user2244670
fonte
10
Woah três desenvolvedores principais em um thread SO. Isso tem que ser algum tipo de recorde ^^
Andreas Mueller

Respostas:

158

De fato, existem várias maneiras de obter "importâncias" do recurso. Com frequência, não existe um consenso estrito sobre o que essa palavra significa.

No scikit-learn, implementamos a importância conforme descrito em [1] (frequentemente citado, mas infelizmente raramente lido ...). Às vezes é chamada de "importância gini" ou "impureza decrescente média" e é definida como a diminuição total na impureza do nó (ponderada pela probabilidade de atingir esse nó (que é aproximada pela proporção de amostras que atingem esse nó)), calculada a média de todos árvores do conjunto.

Na literatura ou em alguns outros pacotes, você também pode encontrar importâncias de recursos implementadas como a "precisão média de diminuição". Basicamente, a idéia é medir a diminuição na precisão dos dados OOB quando você permuta aleatoriamente os valores para esse recurso. Se a redução for baixa, o recurso não será importante e vice-versa.

(Observe que os dois algoritmos estão disponíveis no pacote randomForest R.)

[1]: Breiman, Friedman, "Árvores de classificação e regressão", 1984.

Gilles Louppe
fonte
48
Seria ótimo se essa resposta fosse mencionada na documentação dos atributos / exemplos de importância. Foi procurá-lo por algum tempo também :)
d1337
2
Parece que a pontuação de importância está em valor relativo? Por exemplo, a soma das pontuações de importância de todos os recursos é sempre 1 (veja o exemplo aqui, scikit-learn.org/stable/auto_examples/ensemble/… )
RNA
5
@RNA: Sim, por padrão, as importâncias variáveis ​​são normalizadas no scikit-learn, de modo que elas somarão uma. Você pode contornar isso fazendo um loop sobre os estimadores de base individuais e chamando tree_.compute_feature_importances(normalize=False).
Gilles Louppe
2
@GillesLouppe Você usa amostras fora do saco para medir a redução no MSE para uma floresta de regressores de árvores de decisão em cada árvore? Ou todos os dados de treinamento usados ​​na árvore?
Coke
1
Dois recursos úteis. (1) blog.datadive.net/… um blog de Ando Saabas implementa "a diminuição média da impureza" e também "a redução média da precisão", como mencionado por Gilles. (2) Faça o download e leia a tese de Gilles Louppe.
Mark Teese
54

A maneira usual de calcular os valores de importância do recurso de uma única árvore é a seguinte:

  1. você inicializa uma matriz feature_importances de todos os zeros com tamanho n_features.

  2. você percorre a árvore: para cada nó interno que se divide em um recurso, icalcula a redução de erro desse nó multiplicada pelo número de amostras que foram roteadas para o nó e inclui essa quantidade em feature_importances[i].

A redução do erro depende do critério de impureza que você usa (por exemplo, Gini, Entropy, MSE, ...). É a impureza do conjunto de exemplos que é roteado para o nó interno menos a soma das impurezas das duas partições criadas pela divisão.

É importante que esses valores sejam relativos a um conjunto de dados específico (tanto a redução de erros quanto o número de amostras são específicos do conjunto de dados), portanto, esses valores não podem ser comparados entre diferentes conjuntos de dados.

Até onde eu sei, existem maneiras alternativas de calcular os valores de importância dos recursos nas árvores de decisão. Uma breve descrição do método acima pode ser encontrada em "Elements of Statistical Learning", de Trevor Hastie, Robert Tibshirani e Jerome Friedman.

Peter Prettenhofer
fonte
12

É a proporção entre o número de amostras roteadas para um nó de decisão que envolve esse recurso em qualquer uma das árvores do conjunto sobre o número total de amostras no conjunto de treinamento.

Os recursos envolvidos nos nós de nível superior das árvores de decisão tendem a ver mais amostras, portanto, provavelmente terão mais importância.

Editar : esta descrição está apenas parcialmente correta: as respostas de Gilles e Peter são a resposta correta.

ogrisel
fonte
1
Você sabe se há algum documento / documentação sobre o método exato? por exemplo. Breiman, 2001. Seria ótimo se eu tivesse algum documento adequado, que eu pudesse citar para a metodologia.
precisa saber é o seguinte
@ogrisel, seria ótimo se você pudesse marcar claramente sua resposta como a explicação para a "ponderação". A ponderação por si só não determina a importância do recurso. A "métrica de impureza" ("importância da gini" ou RSS) combinada com os pesos, calculados sobre as árvores, determina a importância geral do recurso. Infelizmente, a documentação sobre o scikit-learn aqui: scikit-learn.org/stable/modules/… não é precisa e menciona incorretamente "profundidade" como a métrica de impureza.
Ariel #
11

Como o @GillesLouppe apontou acima, o scikit-learn atualmente implementa a métrica "média de redução da impureza" para importâncias de recursos. Pessoalmente, acho a segunda métrica um pouco mais interessante, onde você permuta aleatoriamente os valores de cada um dos seus recursos, um por um, e vê o quão pior é o desempenho imediato.

Como o que você procura após a importância do recurso é o quanto cada recurso contribui para o desempenho preditivo do seu modelo geral, a segunda métrica fornece uma medida direta disso, enquanto a "redução média da impureza" é apenas um bom proxy.

Se você estiver interessado, escrevi um pequeno pacote que implementa a métrica Importância da Permutação e pode ser usado para calcular os valores de uma instância de uma classe de floresta aleatória scikit-learn:

https://github.com/pjh2011/rf_perm_feat_import

Edit: Isso funciona para Python 2.7, não 3

Peter
fonte
Olá @ Peter, quando uso seu código, recebo este erro: NameError: name 'xrange' não está definido.
Aizzaac
Oi @Aizzaac. Desculpe, eu sou novo em escrever pacotes, então eu deveria ter notado que escrevi para o Python 2.7. Tente def xrange (x): voltar iter (intervalo (x)) antes de executá-lo
Peter
2

Deixe-me tentar responder à pergunta. código:

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

plotagem decision_tree:
insira a descrição da imagem aqui
Podemos obter compute_feature_importance: [0. , 0.01333333,0.06405596,0.92261071]
Verifique o código-fonte:

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

Tente calcular a importância do recurso:

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

Temos a feature_importance: np.array ([0,1.332,6.418,92.30]).
Depois da normalização, podemos obter o array ([0., 0.01331334, 0.06414793, 0.92253873]), é o mesmo que clf.feature_importances_.
Tenha cuidado para que todas as classes tenham o peso um.

tengfei li
fonte
1

Para quem procura uma referência à documentação do scikit-learn sobre este tópico ou uma referência à resposta de @GillesLouppe:

Em RandomForestClassifier, estimators_attribute é uma lista de DecisionTreeClassifier (conforme mencionado na documentação ). Para calcular o valor feature_importances_para o RandomForestClassifier, no código-fonte do scikit -learn , ele calcula a média de todos os feature_importances_atributos do estimador (todos os DecisionTreeClassifer) no conjunto.

Na documentação do DecisionTreeClassifer , é mencionado que "A importância de um recurso é calculada como a redução total (normalizada) do critério trazido por esse recurso. Também é conhecida como a importância de Gini [1]".

Aqui está um link direto para obter mais informações sobre variáveis ​​e importância do Gini, conforme fornecido pela referência do scikit-learn abaixo.

[1] L. Breiman e A. Cutler, “Random Forests”, http://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm

Makan
fonte