ELI5 i białe pudełka

Dzisiaj będzie krótko. Chciałbym po prostu pokazać wam proste narzędzie ELI5.

Podstawowym sposobem na ocenę naszego świeżo stworzonego modelu jest jego sprawdzenie na pierwotnie dla niego ukrytym zbiorze danych. Jeśli dane podzieliliśmy na stałe zbiory, to możemy w ten sposób całkiem długo testować swoje modele i porównywać wyniki (pokazywałem to między innymi tutaj). Jest to standardowe działanie w czasie produkowania modelu. Po jego zbudowaniu i umieszczeniu na produkcji nie będziemy już go tak mocno rozwijać. Będzie on podejmował decyzje, a my na ich podstawie będziemy podejmować decyzje o poziom wyżej. I w tym momencie wkraczamy na terytorium bardzo ciekawego problemu: Czy chcielibyśmy, aby proces, który nas wspomaga, był jak najbardziej efektywny, ale niekoniecznie łatwy do interpretacji? Czy wolelibyśmy mieć coś, co w 100 procentach da się wytłumaczyć, ale nie dawało to najlepszych możliwych wyników?

Czarne i białe pudełko

Sytuacja, w której stawiamy na najlepszy możliwy proces i nie przejmujemy się czy da się go w ogóle zrozumieć to tzw. czarne pudełko. Do takiego pudełka z jednej strony wrzucamy dane, a z drugiej strony dostajemy predykcję. Zupełnie nie wiemy co się w nim dzieje, ale nie znaleźliśmy lepszego pudełka, więc nie przejmujemy się tym za bardzo.

Natomiast gdy pracujemy dla kogoś, kto musi znać każdy element procesu decyzyjnego, nie możemy użyć czarnego pudełka. Inwestujemy wtedy w jego przeciwieństwo – białe pudełko. Proces tego typu powinien być całkowicie zrozumiały. Które cechy obserwacji są najważniejsze? Dlaczego proces wybrał taką klasę? Co się stanie, gdy podamy mu konkretne dane. Wszystko musi w nim być odkryte.

Często przytoczonymi przykładami są sieci neuronowe (czarne pudełko) i drzewa decyzyjne (białe pudełko). No i mamy jeszcze całą masę modeli, które nie są ani jednym, ani drugim – szare pudełka. Celem tego artykułu jest przybliżenie modułu Pythonowego ELI5 i jego użycie na białym pudełku.

ELI5?

Nazwa modułu ELI5 pochodzi od dokładnie takiego samego angielskiego akronimu, który rozwija się na Explain Like I’m 5, co oznacza wyjaśnij (mi) jak bym miał 5 (lat). Idea jest taka, że prosimy kogoś o wyjaśnienie niezrozumiałego dla nas zagadnienia, tak jakbyśmy mieli 5 lat. Dzięki temu, jeśli osoba tłumacząca odpowiednio się wysili i się postara, uzyskamy bardzo proste i poprawne wyjaśnienie jakiegoś zagadnienia. No i taka jest również idea stojąca za tym modułem – wskazanie w jak najprostszy sposób, które kolumny są najważniejsze dla modelu oraz dlaczego została dokonana konkretna predykcja dla konkretnej obserwacji.

Praktyka

Wytrenujmy sobie model na znanych nam już danych wbudowanych w Scikit-Learn

import pandas as pd
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split

breast_cancer = load_breast_cancer()
X = pd.DataFrame(breast_cancer["data"], 
                 columns = breast_cancer["feature_names"])
y = pd.Series(breast_cancer["target"])

hyperparameters = {"criterion": 'gini', 
                   "max_depth": 5, 
                   "min_samples_leaf": 1, 
                   "min_samples_split": 2, 
                   "n_estimators": 100, 
                   "bootstrap": True, 
                   "max_features": None, 
                   "random_state": 42}

estimator_tree = DecisionTreeClassifier(random_state = hyperparameters["random_state"], 
                                        criterion = hyperparameters["criterion"], 
                                        max_depth = hyperparameters["max_depth"], 
                                        min_samples_leaf = hyperparameters["min_samples_leaf"], 
                                        min_samples_split = hyperparameters["min_samples_split"])

estimator_forest = RandomForestClassifier(random_state = hyperparameters["random_state"], 
                                          criterion = hyperparameters["criterion"], 
                                          max_depth = hyperparameters["max_depth"], 
                                          min_samples_leaf = hyperparameters["min_samples_leaf"], 
                                          min_samples_split = hyperparameters["min_samples_split"], 
                                          n_estimators = hyperparameters["n_estimators"], 
                                          bootstrap = hyperparameters["bootstrap"],
                                          max_features = hyperparameters["max_features"])


X_train, X_test, y_train, y_test = train_test_split(X, y, 
                                                    test_size = 0.25, 
                                                    random_state = 42)
estimator_tree.fit(X = X_train, y = y_train)
estimator_forest.fit(X = X_train, y = y_train)

Po wykonaniu tego kodu uzyskamy obiekt, który będzie wytrenowanym modelem DecisionTreeClassifier. Skoro go wytrenowaliśmy, to możemy użyć ELI5 i podejrzeć, które kolumny były używane i w ogóle były ważne.

import eli5
eli5.explain_weights(estimator_tree, feature_names = list(X_train.columns))

Weight Feature
0.7090

mean concave points
0.1177

worst texture
0.0601

worst radius
0.0352

worst area
0.0293

worst perimeter
0.0173

concave points error
0.0130

area error
0.0100

worst smoothness
0.0068

texture error
0.0016

smoothness error
0

mean area
0

mean smoothness
0

mean compactness
0

mean texture
0

mean symmetry
0

mean fractal dimension
0

radius error
0

mean radius
0

mean perimeter
0

mean concavity
… 10 more …

Widzimy, że informacja uzyskana dzięki ELI5 nie różni się od tego, co uzyskaliśmy “ręcznie” w artykule Które kolumny są dla nas najważniejsze? Warto jeszcze zapoznać się z drugą funkcją, która jest show_prediction. Funkcja ta mówi nam, dlaczego została dokonana taka predykcja. Jest to przydatne, jeśli zastanawiamy się nad konkretnymi obserwacjami, które chcielibyśmy widzieć uzasadnione.

eli5.show_prediction(estimator_tree, doc = X_test.iloc[0], show_feature_values = True)

Contribution? Feature Value
+0.629 <BIAS> 1.000
+0.311 mean concave points 0.038
+0.040 worst radius 14.970
+0.008 area error 30.290
+0.004 worst smoothness 0.143
+0.004 smoothness error 0.007

Co dalej?

Pomysł na ten artykuł polegał na wskazaniu prostego i przydatnego modułu ELI5 do ułatwienia sobie pracy z modelami typu białe pudełko. Dla niektórych może to być przerost formy nad treścią, gdyż takie informacje możemy sobie łatwo uzyskać ręcznie. No i mają rację – bo w tym wypadku ELI5 to niepotrzebny, acz ładny gadżet. Ciekawiej robi się jednak przy próbie wyjaśniania modeli typu czarne pudełko. Jednym z pomysłów na coś takiego jest użycie metody Permutation Importance która również zawarta jest w module ELI5. Ale o tym już w innym artykule.

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *