смущен функцией применения GradientBoostingClassifier

для функции apply вы можете обратиться к здесь

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

grd = GradientBoostingClassifier(n_estimators=n_estimator)
grd_enc = OneHotEncoder()
grd_lm = LogisticRegression()
grd.fit(X_train, y_train)
test_var = grd.apply(X_train)[:, :, 0]
print "test_var.shape", test_var.shape
print "test_var", test_var
grd_enc.fit(grd.apply(X_train)[:, :, 0])
grd_lm.fit(grd_enc.transform(grd.apply(X_train_lr)[:, :, 0]), y_train_lr)

выход, как показано ниже, и путают, какие числа, как 6., 3. и 10. в смысле? И как они связаны с конечным результатом классификации?

test_var.shape (20000, 10)
test_var [[  6.   6.   6. ...,  10.  10.  10.]
 [ 10.  10.  10. ...,   3.   3.   3.]
 [  6.   6.   6. ...,  11.  10.  10.]
 ..., 
 [  6.   6.   6. ...,  10.  10.  10.]
 [  6.   6.   6. ...,  11.  10.  10.]
 [  6.   6.   6. ...,  11.  10.  10.]]

1 ответов


чтобы понять повышение градиента, вам нужно сначала понять отдельные деревья. Я приведу небольшой пример.

вот настройка: небольшая модель GB, обученная набору данных Iris, чтобы предсказать, принадлежит ли цветок к классу 2.

# import the most common dataset
from sklearn.datasets import load_iris
from sklearn.ensemble import GradientBoostingClassifier
X, y = load_iris(return_X_y=True)
# there are 150 observations and 4 features
print(X.shape) # (150, 4)
# let's build a small model = 5 trees with depth no more than 2
model = GradientBoostingClassifier(n_estimators=5, max_depth=2, learning_rate=1.0)
model.fit(X, y==2) # predict 2nd class vs rest, for simplicity
# we can access individual trees
trees = model.estimators_.ravel()
print(len(trees)) # 5
# there are 150 observations, each is encoded by 5 trees, each tree has 1 output
applied = model.apply(X) 
print(applied.shape) # (150, 5, 1)
print(applied[0].T) # [[2. 2. 2. 5. 2.]] - a single row of the apply() result
print(X[0]) # [5.1 3.5 1.4 0.2] - the pbservation corresponding to that row
print(trees[0].apply(X[[0]])) # [2] - 2 is the result of application the 0'th tree to the sample
print(trees[3].apply(X[[0]])) # [5] - 5 is the result of application the 3'th tree to the sample

вы можете видеть, что каждое число в последовательности [2. 2. 2. 5. 2.] произведен model.apply() соответствует выходу одного дерева. Но что означают эти цифры?

мы можем легко проанализировать деревья решений визуально обследование. Вот функция для построения одного

# a function to draw a tree. You need pydotplus and graphviz installed 
# sudo apt-get install graphviz
# pip install pydotplus

from sklearn.externals.six import StringIO  
from IPython.display import Image  
from sklearn.tree import export_graphviz
import pydotplus
def plot_tree(clf):
    dot_data = StringIO()
    export_graphviz(clf, out_file=dot_data, node_ids=True,
                    filled=True, rounded=True, 
                    special_characters=True)
    graph = pydotplus.graph_from_dot_data(dot_data.getvalue())  
    return Image(graph.create_png())

# now we can plot the first tree
plot_tree(trees[0])

enter image description here

вы можете видеть, что каждый узел имеет номер (от 0 до 6). Если мы поместим наш единственный пример в это дерево, он сначала перейдет к узлу #1 (потому что функция x3 имеет значение 0.2 < 1.75), а затем к узлу #2 (потому что функция x2 имеет значение 1.4 < 4.95.

таким же образом, мы можем проанализировать дерево 3, которое произвело выход 5:

plot_tree(trees[3])

enter image description here

здесь наше наблюдение идет сначала к узлу #4, а затем к узлу #5, потому что x1=3.5>2.25 и x2=1.4<4.85. Таким образом, он заканчивается номером 5.

это так просто! каждый номер производится apply() - порядковый номер узла соответствующего дерева, в котором заканчивается образец.

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

в нашем случае, первое дерево (с ее узел #2) дает значение -1.454, другие деревья также дают некоторые значения, а общая сумма их -4.84. Это отрицательный, таким образом, наш пример не относится к классу 2.

values = [trees[i].tree_.value[int(leaf)][0,0] for i, leaf in enumerate(applied[0].ravel())]
print(values) # [-1.454, -1.05, -0.74, -1.016, -0.58] - the values of nodes [2,2,2,5,2] in the corresponding trees
print(sum(values)) # -4.84 - sum of these values is negative -> this is not class 2