Lime vs TreeInterpreter для интерпретации дерева решений

Источник извести: https://github.com/marcotcr/lime

источник treeinterpreter: интерпретатор дерева

Я пытаюсь понять, как DecisionTree сделал свои прогнозы, используя Lime и treeinterpreter. Хотя оба утверждают, что они могут интерпретировать дерево решений в своем описании. Кажется, что оба интерпретируют один и тот же DecisionTree по-разному. То есть, порядок внесения признаков. Как это возможно? если оба ищут одно и то же и пытаются описать одно и то же событие, но придают важность в разностном порядке.

Кому мы должны доверять? Особенно там, где главная особенность имеет значение в прогнозировании.

Код для дерева

import sklearn
import sklearn.datasets
import sklearn.ensemble
import numpy as np
import lime
import lime.lime_tabular
from __future__ import print_function
np.random.seed(1)
from treeinterpreter import treeinterpreter as ti
from sklearn.tree import DecisionTreeClassifier

iris = sklearn.datasets.load_iris()

dt = DecisionTreeClassifier(random_state=42)                
dt.fit(iris.data, iris.target)

n = 100


instances =iris.data[n].reshape(1,-1)

prediction, biases, contributions = ti.predict(dt, instances)


for i in range(len(instances)):
    print ("prediction:",prediction)
    print ("-"*20) 
    print ("Feature contributions:")
    print ("-"*20) 

    for c, feature in sorted(zip(contributions[i], 
                                 iris.feature_names), 
                             key=lambda x: ~abs(x[0].any())):

        print (feature, c)

Код для извести

import sklearn
import sklearn.datasets
import sklearn.ensemble
import numpy as np
import lime
import lime.lime_tabular
from __future__ import print_function
np.random.seed(1)
from sklearn.tree import DecisionTreeClassifier

iris = sklearn.datasets.load_iris()

dt = DecisionTreeClassifier(random_state=42)                
dt.fit(iris.data, iris.target)

explainer = lime.lime_tabular.LimeTabularExplainer(iris.data, feature_names=iris.feature_names, 
                                                   class_names=iris.target_names, 
                                                   discretize_continuous=False)

n = 100


exp = explainer.explain_instance(iris.data[n], dt.predict_proba, num_features=4, top_labels=2)

exp.show_in_notebook(show_table=True,  predict_proba= True , show_predicted_value = True , show_all=False)

Давайте посмотрим сначала на выход дерева.

enter image description here

так что она правильно сказать, что это был virginica. Однако, назначив важность в

1) ширина лепестка (см), затем длина лепестка (см)

Теперь давайте посмотрим на выход извести

enter image description here

Да, он говорит, что алгоритм предсказал virginica, однако, глядя на то, как он сделал эту классификацию, мы ясно видим следующее

1) длина лепестка (см)> ширина лепестка (см) в извести вместо длины лепестка (см) <ширина лепестка (см), как показано на дереве

2), где ширина сепалы и длина сепалы были предсказаны равной нулю, требования к извести определенной величины, как показано в загруженных изображениях

Что здесь происходит?

Проблема возрастает, когда функции 1000+, где каждая цифра имеет значение для принятия решения.

Ответ 1

Почему возможно, чтобы оба подхода имели разные результаты?

Лайм: Краткое объяснение того, как это работает, взятое со страницы github:

Интуитивно объяснение представляет собой локальное линейное приближение модельного поведения. Хотя модель может быть очень сложной во всем мире, ее проще приблизить к окрестности конкретного экземпляра. Обращаясь к модели как к черному ящику, мы рассматриваем пример, который мы хотим объяснить, и изучим вокруг него редкую линейную модель, как объяснение. На рисунке ниже показана интуиция для этой процедуры. Модельная функция решения представлена синим/розовым фоном и явно нелинейна. Яркий красный крест - это объясняемый экземпляр (пусть его называют X). Мы пробуем экземпляры вокруг X и взвешиваем их в соответствии с их близостью к X (вес здесь обозначается размером). Затем мы изучаем линейную модель (пунктирную линию), которая аппроксимирует модель хорошо в окрестности X, но не обязательно глобально.

Более подробная информация содержится в различных ссылках на странице github.

treeinterpreter: объяснение того, как это работает, доступно на http://blog.datadive.net/interpreting-random-forests/ (это для регрессии, пример классификации, который работает очень аналогично, можно найти здесь).

Короче: предположим, что у нас есть узел, который сравнивает функцию F с некоторым значением и разбивает экземпляры на основе этого. Предположим, что 50% всех экземпляров, достигающих этого узла, относятся к классу C Предположим, что у нас есть новый экземпляр, и он получает привязку к левому дочернему узлу этого узла, где теперь 80% всех экземпляров принадлежат классу C Затем вклад функции F для этого решения вычисляется как 0.8 - 0.5 = 0.3 (плюс дополнительные члены, если на пути к листу больше узлов, которые также используют функцию F).

Сравнение: Важно отметить, что Lime - это независимый от модели метод (не определенный для деревьев принятия решений /RFs), который основан на локальном линейном приближении. С другой стороны, Treeinterpreter работает точно так же, как и в самом Дереве решений, и действительно смотрит, какие функции фактически используются при сравнении алгоритма. Поэтому они действительно принципиально делают совсем другие вещи. Лайм говорит: "Особенность важна, если мы немного ее шевелим, и это приводит к другому прогнозу". Treeinterpreter говорит: "Особенность важна, если ее сравнить с порогом в одном из наших узлов, и это заставило нас принять раскол, который резко изменил наше предсказание".


Кому доверять?

Трудно ответить окончательно. Вероятно, они полезны по-своему. Интуитивно вы можете склониться к указателю на дерево с первого взгляда, потому что он был специально создан для деревьев принятия решений. Однако рассмотрим следующий пример:

  • Корневой узел: 50% экземпляров класса 0, 50% класса 1. IF F <= 50, идти влево, в противном случае идти вправо.
  • Левый ребенок: 48% экземпляров класса 0, класс 52% 1. Под ним ниже.
  • Правый ребенок: 99% экземпляров класса 0, 1% экземпляров класса 1. Subtree ниже этого.

Такая настройка возможна, если большинство экземпляров уходят влево, только некоторые права. Теперь предположим, что у нас есть экземпляр с F = 49 который был назначен для левого и в конечном итоге назначенного класса 1. Treeinterpreter не заботится, что F действительно близко к концу с другой стороны уравнения в корневом узле и назначает только низкий вклад 0.48 - 0.50 = -0.02. Лайм заметит, что изменение F просто немного изменит шансы.

Какой из них прав? Это не совсем понятно. Вы могли бы сказать, что F был действительно важен, потому что если бы это было немного иначе, предсказание было бы другим (тогда побеждает лиза). Вы также можете утверждать, что F не вносил свой вклад в наше окончательное предсказание, потому что мы едва ли приблизились к решению после проверки его ценности и все же должны были исследовать многие другие функции впоследствии. Затем выигрывает treeinterpreter.

Чтобы получить более полную идею здесь, это может помочь также на самом деле запечатлеть выработанное Дерево решений. Затем вы можете вручную следовать своему пути решения и решать, какие функции вы считаете важными, и/или посмотреть, можете ли вы понять, почему оба Lime и treeinterpreter говорят, что они говорят.