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.