Відносна змінна важливість для підвищення рівня


33

Я шукаю пояснення того, як обчислюється відносна змінна важливість у градієнтних підсилених деревах, що не є надто загальним / спрощеним, як:

Заходи ґрунтуються на кількості вибраних змінних для розщеплення, зважених вдосконаленням у формі квадрата в результаті кожного розколу та усередненому для всіх дерев . [ Еліт та ін. 2008 р., Робочий посібник з посиленими регресійними деревами ]

І це менш абстрактно, ніж:

Ij2^(T)=t=1J1it2^1(vt=j)

Там , де підсумовування ведеться по нетерміналу вузли з термінальному вузла дерева , є змінним розщеплення , пов'язаний з вузлом і є відповідним емпіричним поліпшенням в квадраті помилки в результаті розщеплення, визначеного як , де - ліва і права відповідна дочка відповідно, а - відповідні суми ваг. J T v t t ^ i 2 t i 2 ( R l , R r ) = w l w rtJTvttit2^i2(Rл,Rr)=шлшrшл+шr(ул¯-уr¯)2ул¯,уr¯шл,шr[ Friedman 2001, Жадне наближення функції: машина для підвищення градієнта ]

Нарешті, я не вважав, що Елементи статистичного навчання (Hastie et al. 2008) є дуже корисним для читання тут, оскільки відповідний розділ (10.13.1 стор. 367) на смак дуже схожий на другу посилання вище (що може бути пояснено) тим, що Фрідман є співавтором книги).

PS: Я знаю , що відносні заходи змінної важливості задаються summary.gbm в пакеті GBM R. Я спробував дослідити вихідний код, але, здається, не знаю, де відбувається фактичне обчислення.

Брауні вказує: мені цікаво, як отримати ці сюжети в Р.


Я просто додав новий відповідь на пов'язаний питання про те, як побудувати змінне значення за класами , які можуть бути корисні stackoverflow.com/a/51952918/3277050
see24

Відповіді:


55

Я використовую код sklearn , оскільки він, як правило, набагато чистіший за Rкод.

Ось реалізація властивості feature_imporences GradientBoostingClassifier (я видалив деякі рядки коду, які перешкоджають концептуальному матеріалу)

def feature_importances_(self):
    total_sum = np.zeros((self.n_features, ), dtype=np.float64)
    for stage in self.estimators_:
        stage_sum = sum(tree.feature_importances_
                        for tree in stage) / len(stage)
        total_sum += stage_sum

    importances = total_sum / len(self.estimators_)
    return importances

Це досить легко зрозуміти. self.estimators_являє собою масив, що містить окремі дерева в бустері, тому цикл for є ітерацією над окремими деревами. Є одна хитка з

stage_sum = sum(tree.feature_importances_
                for tree in stage) / len(stage)

це турбота про небінарний випадок відповіді. Тут ми вміщуємо кілька дерев на кожному етапі в один спосіб. Найпростіший концептуально - зосередитись на двійковому випадку, де сума має одну суму, і це справедливо tree.feature_importances_. Тож у двійковому випадку ми можемо переписати це все як

def feature_importances_(self):
    total_sum = np.zeros((self.n_features, ), dtype=np.float64)
    for tree in self.estimators_:
        total_sum += tree.feature_importances_ 
    importances = total_sum / len(self.estimators_)
    return importances

Отже, на словах, підсумуйте особливості імпорту окремих дерев, а потім розділіть на загальну кількість дерев . Залишається побачити, як обчислити імпорт функцій для одного дерева.

Розрахунок важливості дерева реалізується на рівні цитону , але він все ще може бути виконаний. Ось очищена версія коду

cpdef compute_feature_importances(self, normalize=True):
    """Computes the importance of each feature (aka variable)."""

    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

    return importances

Це досить просто. Ітерація через вузли дерева. Поки ви не знаходитесь у листовому вузлі, обчисліть зважене зменшення чистоти вузла від розколу на цьому вузлі та віднесіть його до функції, яка була розділена на

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)

Потім, по закінченні, розділіть це все на загальну вагу даних (у більшості випадків - кількість спостережень)

importances /= nodes[0].weighted_n_node_samples

Варто нагадати, що домішка - це загальна назва для метрики, яку слід використовувати при визначенні того, що потрібно розщепити під час вирощування дерева. У цьому світлі ми просто підсумовуємо, скільки розщеплення на кожну функцію дозволило нам зменшити домішки у всіх розщепленнях дерева.

В умовах збільшення градієнта ці дерева завжди регресують (мінімізуючи помилку в квадраті), підходять до градієнта функції втрат.


Дякую за цю дуже детальну відповідь. Дайте мені трохи часу, щоб ретельно пройти його, перш ніж я прийму.
Антуан

4
Хоча здається, що можна використовувати різні критерії домішки, індекс Джині не був критерієм, який використовував Фрідман. Як згадувалося в моєму запитанні та рядку 878 вашого третього посилання, Фрідман використав критерій домішки середнього квадрату помилки з оцінкою поліпшення . Якби ви могли оновити цей розділ своєї відповіді, це було б чудово. І так, ти маєш рацію, здається, що ваги справді є кількістю спостережень.
Антуан

3
а може, це зробить вашу відповідь ще краще зберегти обидві частини про індекс Джині та оригінальний критерій Фрідмана, підкреслюючи, що перша використовується для класифікації, а друга для регресії?
Антуан

Антуан, дякую за це оновлення. Дійсно корисно знати, що середня квадратична помилка є критеріями вдосконалення, які використовуються для дерев регресії. Не очевидно було, як це буде використано для класифікації. Однак, навіть при збільшенні градієнта для класифікації, я думаю, що дерева регресії все ще використовуються, на відміну від дерев класифікації. Принаймні, в python, регресійний аналіз робиться на поточну помилку на кожному етапі підвищення.
Досить Нерді

Ви, хлопці, правильні щодо регресії дерев.
Метью Друрі
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.