W jaki sposób są określane cechy_importowe w RandomForestClassifier?

125

Mam zadanie klasyfikacyjne z szeregami czasowymi jako danymi wejściowymi, gdzie każdy atrybut (n = 23) reprezentuje określony punkt w czasie. Oprócz absolutnego wyniku klasyfikacji chciałbym się dowiedzieć, które atrybuty / daty wpływają na wynik w jakim stopniu. Dlatego używam tylko programu feature_importances_, który działa dobrze dla mnie.

Chciałbym jednak wiedzieć, w jaki sposób są one obliczane i który środek / algorytm jest używany. Niestety nie mogłem znaleźć żadnej dokumentacji na ten temat.

user2244670
źródło
10
Woah trzech głównych deweloperów w jednym wątku SO. To musi być jakiś rekord ^^
Andreas Mueller

Odpowiedzi:

158

Rzeczywiście istnieje kilka sposobów uzyskania „ważności” funkcji. Jak to często bywa, nie ma ścisłej zgody co do znaczenia tego słowa.

W scikit-learn realizujemy znaczenie opisane w [1] (często cytowane, ale niestety rzadko czytane ...). Jest czasami nazywany „ważnością giniego” lub „średnim zmniejszeniem zanieczyszczeń” i jest definiowany jako całkowity spadek zanieczyszczenia węzła (ważony prawdopodobieństwem dotarcia do tego węzła (które jest przybliżone przez odsetek próbek docierających do tego węzła)) uśredniony dla wszystkich drzewa zespołu.

W literaturze lub w niektórych innych pakietach można również znaleźć znaczenia funkcji zaimplementowane jako „średni spadek dokładności”. Zasadniczo chodzi o zmierzenie spadku dokładności danych OOB, gdy losowo permutujesz wartości dla tej funkcji. Jeśli spadek jest niski, funkcja nie jest ważna i odwrotnie.

(Należy pamiętać, że oba algorytmy są dostępne w pakiecie randomForest R.)

[1]: Breiman, Friedman, „Drzewa klasyfikacji i regresji”, 1984.

Gilles Louppe
źródło
48
Byłoby wspaniale, gdyby ta odpowiedź została wymieniona w dokumentacji dotyczącej ważnych atrybutów / przykładu.
Szukałem
2
Wydaje się, że ocena ważności ma względną wartość? Na przykład suma ocen ważności wszystkich cech zawsze wynosi 1 (patrz przykład tutaj scikit-learn.org/stable/auto_examples/ensemble/… )
RNA
5
@RNA: Tak, domyślnie wartości importu zmiennych są normalizowane w scikit-learn, tak że sumują się do jednego. Możesz to obejść, przeglądając poszczególne estymatory bazowe i wywołując tree_.compute_feature_importances(normalize=False).
Gilles Louppe
2
@GillesLouppe Czy używasz próbek spoza worka do pomiaru redukcji MSE dla lasu regresorów drzew decyzyjnych w każdym drzewie? A może wszystkie dane treningowe używane w drzewie?
Cokes
1
Dwa przydatne zasoby. (1) blog.datadive.net/ ... blog Ando Saabasa wprowadza zarówno „średni spadek zanieczyszczeń”, jak i „średni spadek dokładności”, jak wspomniał Gilles. (2) Pobierz i przeczytaj pracę Gillesa Louppe.
Mark Teese,
54

Typowy sposób obliczania wartości ważności cech w pojedynczym drzewie jest następujący:

  1. inicjalizujesz tablicę feature_importanceswszystkich zer o rozmiarze n_features.

  2. przechodzisz przez drzewo: dla każdego węzła wewnętrznego, który dzieli się na obiekt i, obliczasz redukcję błędów tego węzła pomnożoną przez liczbę próbek, które zostały skierowane do węzła i dodajesz tę ilość do feature_importances[i].

Redukcja błędu zależy od kryterium zanieczyszczenia, którego używasz (np. Gini, Entropy, MSE, ...). Jest to zanieczyszczenie zestawu przykładów, które jest kierowane do węzła wewnętrznego pomniejszone o sumę zanieczyszczeń z dwóch partycji utworzonych przez podział.

Ważne jest, aby te wartości były odniesione do określonego zbioru danych (zarówno redukcja błędów, jak i liczba próbek są specyficzne dla zestawu danych), dlatego wartości te nie mogą być porównywane między różnymi zbiorami danych.

O ile mi wiadomo, istnieją alternatywne sposoby obliczania wartości ważności cech w drzewach decyzyjnych. Krótki opis powyższej metody można znaleźć w „Elements of Statistical Learning” Trevora Hastiego, Roberta Tibshirani i Jerome'a ​​Friedmana.

Peter Prettenhofer
źródło
12

Jest to stosunek liczby próbek skierowanych do węzła decyzyjnego obejmującego tę cechę w dowolnym z drzew zespołu do całkowitej liczby próbek w zbiorze uczącym.

Funkcje, które są zaangażowane w węzły najwyższego poziomu drzew decyzyjnych, zwykle zawierają więcej próbek, dlatego prawdopodobnie będą miały większe znaczenie.

Edycja : ten opis jest tylko częściowo poprawny: odpowiedzi Gillesa i Petera są poprawne.

ogrisel
źródło
1
Czy wiesz, czy istnieje jakiś dokument / dokumentacja na temat dokładnej metody? na przykład. Breiman, 2001. Byłoby wspaniale, gdybym miał jakiś odpowiedni dokument, który mógłbym przytoczyć jako metodologię.
user2244670
@ogrisel byłoby wspaniale, gdybyś mógł wyraźnie oznaczyć swoją odpowiedź jako wyjaśnienie „wagi”. Samo ważenie nie decyduje o znaczeniu funkcji. „Metryka zanieczyszczeń” („ważność giniego” lub RSS) w połączeniu z wagami uśrednionymi dla drzew określa ogólne znaczenie funkcji. Niestety, dokumentacja dotycząca scikit-learn tutaj: scikit-learn.org/stable/modules/… nie jest dokładna i nieprawidłowo wymienia „głębokość” jako metrykę zanieczyszczenia.
Ariel
11

Jak @GillesLouppe wskazał powyżej, scikit-learn obecnie implementuje metrykę „średniego spadku zanieczyszczeń” dla ważności funkcji. Osobiście uważam, że druga metryka jest nieco bardziej interesująca, w której losowo permutujesz wartości dla każdej funkcji jedna po drugiej i sprawdzasz, o ile gorsza jest wydajność po wyjęciu z torby.

Ponieważ tym, czego szukasz, jeśli chodzi o ważność funkcji, jest to, w jakim stopniu każda funkcja przyczynia się do ogólnej wydajności predykcyjnej twojego modelu, druga miara w rzeczywistości daje ci bezpośrednią miarę tego, podczas gdy „zanieczyszczenie średniego spadku” jest po prostu dobrym proxy.

Jeśli jesteś zainteresowany, napisałem mały pakiet, który implementuje metrykę Permutation Importance i może być używany do obliczania wartości z instancji losowej klasy lasu scikit-learn:

https://github.com/pjh2011/rf_perm_feat_import

Edycja: to działa dla Pythona 2.7, a nie 3

Piotr
źródło
Cześć @Peter, kiedy używam twojego kodu, pojawia się ten błąd: NameError: nazwa „xrange” nie jest zdefiniowana.
Aizzaac
Cześć @Aizzaac. Przepraszam, że jestem nowy w pisaniu pakietów, więc powinienem był zauważyć, że napisałem go dla Pythona 2.7. Wypróbuj def xrange (x): return iter (range (x)) przed uruchomieniem
Peter
2

Spróbuję odpowiedzieć na pytanie. kod:

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

Działka drzewa decyzyjnego:
wprowadź opis obrazu tutaj.
Możemy uzyskać compute_feature_importance: [0. , 0.01333333,0.06405596,0.92261071]
Sprawdź kod źródłowy:

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

Spróbuj obliczyć ważność funkcji:

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

Otrzymujemy feature_importance: np.array ([0,1.332,6.418,92.30]).
Po znormalizowaniu możemy otrzymać tablicę ([0., 0.01331334, 0.06414793, 0.92253873]), to jest to samo co clf.feature_importances_.
Uważaj, wszystkie klasy mają mieć wagę jeden.

tengfei li
źródło
1

Dla tych, którzy szukają odniesienia do dokumentacji scikit-learn na ten temat lub odniesienia do odpowiedzi @GillesLouppe:

W RandomForestClassifier estimators_atrybut jest listą DecisionTreeClassifier (jak wspomniano w dokumentacji ). Aby obliczyć feature_importances_dla RandomForestClassifier, w kodzie źródłowym scikit-learn uśrednia wszystkie feature_importances_atrybuty estymatora (wszystkie DecisionTreeClassifer) w zespole.

W dokumentacji DecisionTreeClassifera wspomina się, że „Ważność cechy jest obliczana jako (znormalizowana) całkowita redukcja kryterium wynikającego z tej cechy. Znana jest również jako znaczenie Giniego [1]”.

Tutaj jest bezpośredni link do dalszych informacji na temat zmiennych i ważności Gini, zgodnie z odnośnikiem scikit-learn poniżej.

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

Makan
źródło