Saya akan menggunakan kode sklearn , karena umumnya jauh lebih bersih daripada R
kode.
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.