Как определяется feature_importances в RandomForestClassifier?

125

У меня есть задача классификации с временными рядами в качестве входных данных, где каждый атрибут (n = 23) представляет определенный момент времени. Помимо абсолютного результата классификации, хотелось бы узнать, какие атрибуты / даты в какой степени влияют на результат. Поэтому я просто использую тот feature_importances_, который мне подходит.

Однако я хотел бы знать, как они рассчитываются и какая мера / алгоритм используется. К сожалению, мне не удалось найти никакой документации по этой теме.

user2244670
источник
10
Вау, три основных разработчика в одном потоке SO. Это должен быть какой-то рекорд ^^
Андреас Мюллер

Ответы:

158

На самом деле есть несколько способов добиться «важности» функций. Как правило, нет единого мнения о том, что означает это слово.

В scikit-learn мы реализуем важность, как описано в [1] (часто цитируется, но, к сожалению, редко читается ...). Иногда его называют «важность Джини» или «среднее уменьшение примесей» и определяют как общее уменьшение примесей в узле (взвешенное по вероятности достижения этого узла (которая аппроксимируется долей выборок, достигших этого узла)), усредненное по всем деревья ансамбля.

В литературе или в некоторых других пакетах вы также можете найти значения функций, реализованные как «среднее уменьшение точности». По сути, идея состоит в том, чтобы измерить снижение точности данных OOB, когда вы случайным образом переставляете значения для этой функции. Если снижение небольшое, то характеристика не важна, и наоборот.

(Обратите внимание, что оба алгоритма доступны в пакете randomForest R.)

[1]: Брейман, Фридман, «Деревья классификации и регрессии», 1984.

Жиль Лупп
источник
48
Было бы здорово, если бы этот ответ был упомянут в документации по атрибутам / примеру важности.
Я
2
Кажется, оценка важности выражается в относительной ценности? Например, сумма оценок важности всех функций всегда равна 1 (см. Пример здесь scikit-learn.org/stable/auto_examples/ensemble/… )
RNA
5
@RNA: Да, по умолчанию значения переменных нормализованы в scikit-learn, так что они в сумме равны единице. Вы можете обойти это, перебрав отдельные базовые оценщики и позвонив tree_.compute_feature_importances(normalize=False).
Gilles Louppe
2
@GillesLouppe Используете ли вы нестандартные выборки для измерения сокращения MSE для леса регрессоров дерева решений в каждом дереве? Или все данные обучения, используемые в дереве?
Cokes
1
Два полезных ресурса. (1) blog.datadive.net/… блог Андо Саабаса реализует как «среднее уменьшение примесей», так и «среднее снижение точности», как упомянул Жиль. (2) Загрузите и прочтите диссертацию Жиля Луппа.
Марк Тиз
54

Обычный способ вычисления значений важности функции для одного дерева следующий:

  1. вы инициализируете массив feature_importancesвсех нулей размером n_features.

  2. вы перемещаетесь по дереву: для каждого внутреннего узла, который разбивается на объект, iвы вычисляете уменьшение ошибок этого узла, умноженное на количество выборок, которые были направлены на узел, и добавляете это количество к feature_importances[i].

Уменьшение ошибки зависит от критерия примеси, который вы используете (например, Джини, Энтропия, MSE, ...). Это примесь набора примеров, который направляется на внутренний узел, за вычетом суммы примесей двух разделов, созданных в результате разделения.

Важно, чтобы эти значения относились к определенному набору данных (как уменьшение ошибок, так и количество выборок зависят от набора данных), поэтому эти значения нельзя сравнивать между разными наборами данных.

Насколько мне известно, существуют альтернативные способы вычисления значений важности функций в деревьях решений. Краткое описание вышеуказанного метода можно найти в «Элементах статистического обучения» Тревора Хасти, Роберта Тибширани и Джерома Фридмана.

Петер Преттенхофер
источник
12

Это соотношение между количеством выборок, направленных на узел принятия решения, включающий эту функцию в любом из деревьев ансамбля, к общему количеству выборок в обучающем наборе.

Функции, которые задействованы в узлах верхнего уровня деревьев решений, имеют тенденцию видеть больше выборок, поэтому, вероятно, имеют большее значение.

Изменить : это описание верно только частично: ответы Жиля и Питера - правильный ответ.

ogrisel
источник
1
Вы знаете, есть ли бумага / документация о точном методе? например. Breiman, 2001. Было бы здорово, если бы у меня был какой-нибудь подходящий документ, на который я мог бы ссылаться в качестве методологии.
user2244670
@ogrisel, было бы здорово, если бы вы могли четко обозначить свой ответ как объяснение "взвешивания". Само по себе взвешивание не определяет важность характеристики. «Показатель примеси» («важность джини» или RSS) в сочетании с весами, усредненными по деревьям, определяет общую важность функции. К сожалению, документация по scikit-learn здесь: scikit-learn.org/stable/modules/… не является точной и неправильно упоминает «глубину» как метрику примесей.
Ариэль
11

Как отметил @GillesLouppe выше, scikit-learn в настоящее время реализует метрику «среднего уменьшения примесей» для важности функций. Я лично считаю, что второй показатель немного более интересен, когда вы случайным образом переставляете значения для каждой из ваших функций одно за другим и видите, насколько хуже ваша производительность вне сумки.

Поскольку то, что вам нужно для важности функции, - это то, насколько каждая функция вносит вклад в прогнозирующую производительность вашей общей модели, вторая метрика фактически дает вам прямую оценку этого, тогда как «среднее уменьшение примесей» является просто хорошим показателем.

Если вам интересно, я написал небольшой пакет, который реализует метрику важности перестановки и может использоваться для вычисления значений из экземпляра класса случайного леса scikit-learn:

https://github.com/pjh2011/rf_perm_feat_import

Изменить: это работает для Python 2.7, а не 3

Питер
источник
Привет, @Peter, когда я использую ваш код, я получаю эту ошибку: NameError: имя 'xrange' не определено.
Aizzaac
Привет @Aizzaac. Извините, я новичок в написании пакетов, поэтому я должен был отметить, что написал его для Python 2.7. Попробуйте def xrange (x): return iter (range (x)) перед его запуском
Питер,
2

Позвольте мне попытаться ответить на вопрос. код:

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

solution_tree plot:
введите описание изображения здесь
Мы можем получить compute_feature_importance: [0. , 0.01333333,0.06405596,0.92261071]
Проверить исходный код:

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

Попробуйте рассчитать важность функции:

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

Получаем feature_importance: np.array ([0,1.332,6.418,92.30]).
После нормализации мы можем получить массив ([0., 0.01331334, 0.06414793, 0.92253873]), это то же самое, что clf.feature_importances_.
Будьте осторожны, все классы должны иметь вес один.

Tengfei li
источник
1

Для тех, кто ищет ссылку на документацию scikit-learn по этой теме или ссылку на ответ @GillesLouppe:

В RandomForestClassifier estimators_атрибутом является список DecisionTreeClassifier (как указано в документации ). Чтобы вычислить feature_importances_для RandomForestClassifier, в исходном коде scikit-learn , он усредняет по всем оценкам (всем DecisionTreeClassifer)feature_importances_ атрибутам в ансамбле.

В документации DecisionTreeClassifer упоминается, что «Важность функции вычисляется как (нормализованное) общее сокращение критерия, создаваемого этой функцией. Это также известно как важность Джини [1]».

Вот прямая ссылка для получения дополнительной информации о переменной и важности Джини, как указано в ссылке scikit-learn ниже.

[1] Л. Брейман и А. Катлер, «Случайные леса», http://www.stat.berkeley.edu/~breiman/RandomForests/cc_home.htm

Макан
источник