Pentingnya variabel relatif untuk Meningkatkan

33

Saya sedang mencari penjelasan tentang betapa pentingnya variabel relatif dihitung dalam Gradient Boosted Trees yang tidak terlalu umum / sederhana seperti:

Langkah-langkah didasarkan pada berapa kali variabel dipilih untuk pemisahan, ditimbang oleh peningkatan kuadrat untuk model sebagai hasil dari setiap perpecahan, dan rata-rata di semua pohon . [ Elith et al. 2008, Panduan kerja untuk meningkatkan pohon regresi ]

Dan itu kurang abstrak dari:

sayaj2^(T)=t=1J-1sayat2^1(vt=j)

Jika penjumlahannya melebihi nonterminal nodes dari -terminal node tree , adalah variabel pemisahan yang terkait dengan node , dan adalah peningkatan empiris yang sesuai dalam kuadrat kesalahan sebagai hasil dari pemisahan, didefinisikan sebagai , di mana masing-masing adalah sarana respons putri kiri dan kanan masing-masing, dan adalah jumlah bobot yang sesuai. J T v t t ^ i 2 t i 2 ( R l , R r ) = w l w rtJTvttsayat2^ ¯ y l , ¯ y r wl,wrsaya2(Rl,Rr)=wlwrwl+wr(yl¯-yr¯)2yl¯,yr¯wl,wr[ Friedman 2001, perkiraan fungsi Greedy: mesin peningkat gradien ]

Akhirnya, saya tidak menemukan Elemen Pembelajaran Statistik (Hastie et al. 2008) sangat membantu dibaca di sini, karena bagian yang relevan (10.13.1 halaman 367) rasanya sangat mirip dengan referensi kedua di atas (yang mungkin dijelaskan oleh fakta bahwa Friedman adalah rekan penulis buku).

PS: Saya tahu ukuran kepentingan variabel relatif diberikan oleh summary.gbm dalam paket gbm R. Saya mencoba menjelajahi kode sumber, tetapi sepertinya saya tidak dapat menemukan di mana perhitungan yang sebenarnya terjadi.

Brownie poin: Saya ingin tahu bagaimana mendapatkan plot ini di R.

Antoine
sumber
Saya baru saja menambahkan jawaban baru untuk pertanyaan terkait tentang bagaimana memplot variabel penting menurut kelas yang mungkin membantu stackoverflow.com/a/51952918/3277050
see24

Jawaban:

55

Saya akan menggunakan kode sklearn , karena umumnya jauh lebih bersih daripada Rkode.

Inilah implementasi properti feature_importances dari GradientBoostingClassifier (saya menghapus beberapa baris kode yang menghalangi hal-hal konseptual)

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

Ini cukup mudah dimengerti. self.estimators_adalah array yang berisi pohon individu di booster, sehingga loop untuk iterasi di atas pohon individu. Ada satu masalah dengan

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

ini menangani kasus respons non-biner. Di sini kita cocokkan beberapa pohon di setiap tahap dengan cara satu lawan satu. Secara konseptual paling sederhana untuk fokus pada kasus biner, di mana jumlah memiliki satu ringkasan, dan ini adil tree.feature_importances_. Jadi dalam kasus biner, kita dapat menulis ulang semua ini sebagai

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

Jadi, dengan kata lain, jumlah fitur penting dari masing-masing pohon, lalu bagi dengan jumlah total pohon . Tetap melihat bagaimana menghitung kepentingan fitur untuk satu pohon.

Perhitungan pentingnya pohon diimplementasikan pada tingkat cython , tetapi masih bisa ditindaklanjuti. Ini versi kode yang sudah dibersihkan

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

Ini sangat sederhana. Iterasi melalui simpul pohon. Selama Anda tidak berada di simpul daun, hitung penurunan tertimbang dalam kemurnian simpul dari pemisahan di simpul ini, dan berikan atribut pada fitur yang dipecah pada

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)

Kemudian, setelah selesai, bagi semuanya dengan bobot total data (dalam kebanyakan kasus, jumlah pengamatan)

importances /= nodes[0].weighted_n_node_samples

Patut diingat bahwa pengotor adalah nama umum untuk metrik untuk digunakan saat menentukan apa yang harus dibuat perpecahan saat menanam pohon. Dalam terang itu, kami hanya meringkas berapa banyak pemisahan pada setiap fitur memungkinkan kami untuk mengurangi pengotor di semua celah di pohon.

Dalam konteks meningkatkan gradien, pohon-pohon ini selalu pohon regresi (meminimalkan kesalahan kuadrat dengan rakus) cocok dengan gradien fungsi kerugian.

Matthew Drury
sumber
Terima kasih banyak atas jawaban yang sangat terperinci ini. Biarkan saya waktu untuk hati-hati melewatinya sebelum saya menerimanya.
Antoine
4
Meskipun tampaknya berbagai kriteria pengotor dapat digunakan, indeks Gini bukanlah kriteria yang digunakan oleh Friedman. Seperti yang disebutkan dalam pertanyaan saya dan baris 878 dari tautan ketiga Anda, Friedman menggunakan kriteria pengotor kesalahan kuadrat rata - rata dengan skor peningkatan . Jika Anda dapat memperbarui bagian jawaban ini, itu akan bagus. Dan ya, Anda benar, tampaknya bobotnya memang jumlah pengamatan.
Antoine
3
atau mungkin itu akan membuat jawaban Anda lebih baik untuk menjaga kedua bagian tentang indeks Gini dan kriteria asli Friedman, menekankan bahwa yang pertama digunakan untuk klasifikasi dan yang kedua untuk regresi?
Antoine
Antoine, terima kasih atas pembaruan ini. Sangat membantu untuk mengetahui bahwa mean squared error adalah kriteria perbaikan yang digunakan untuk pohon regresi. Tidak jelas bagaimana itu akan digunakan untuk klasifikasi. Namun, bahkan dalam peningkatan gradien untuk klasifikasi, saya pikir pohon regresi masih digunakan, berlawanan dengan pohon klasifikasi. Setidaknya dalam python, analisis regresi sedang dilakukan pada kesalahan saat ini di setiap tahap peningkatan.
Fairly Nerdy
Kalian benar tentang pohon regresi.
Matthew Drury