Samouczek Scikit-Learn: Jak zainstalować i przykłady Scikit-Learn

Czym jest Scikit-learn?

Nauka scikitu jest open-source Python biblioteka do uczenia maszynowego. Obsługuje najnowocześniejsze algorytmy, takie jak KNN, XGBoost, random forest i SVM. Jest zbudowana na bazie NumPy. Scikit-learn jest szeroko stosowany w konkursach Kaggle, a także w wybitnych firmach technologicznych. Pomaga w przetwarzaniu wstępnym, redukcji wymiarowości (wybór parametrów), klasyfikacji, regresji, klastrowaniu i wyborze modelu.

Scikit-learn ma najlepszą dokumentację ze wszystkich bibliotek open source. Zapewnia interaktywny wykres pod adresem https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Jak działa Scikit Learn
Jak działa Scikit Learn

Scikit-learn nie jest bardzo trudny w użyciu i zapewnia doskonałe wyniki. Jednakże scikit Learn nie obsługuje obliczeń równoległych. Można z nim uruchomić algorytm głębokiego uczenia się, ale nie jest to rozwiązanie optymalne, zwłaszcza jeśli wiesz, jak korzystać z TensorFlow.

Jak pobrać i zainstalować Scikit-learn

Teraz w tym Python Tutorial Scikit-learn, dowiemy się jak pobrać i zainstalować Scikit-learn:

1 opcji: AWS

scikit-learn może być używany w AWS. Proszę odnosić się Obraz okna dokowanego z preinstalowanym modułem scikit-learn.

Aby użyć wersji deweloperskiej, użyj polecenia in Jupyter

import sys
!{sys.executable} -m pip install git+git://github.com/scikit-learn/scikit-learn.git

2 opcji: Mac lub Windows za pomocą Anacondy

Aby dowiedzieć się więcej na temat instalacji Anacondy, zobacz https://www.guru99.com/download-install-tensorflow.html

Niedawno twórcy scikit wydali wersję rozwojową, która rozwiązuje typowe problemy napotykane w bieżącej wersji. Uznaliśmy, że wygodniej jest używać wersji dla programistów zamiast wersji bieżącej.

Jak zainstalować scikit-learn w środowisku Conda

Jeśli zainstalowałeś scikit-learn ze środowiskiem conda, wykonaj krok, aby zaktualizować do wersji 0.20

Krok 1) Aktywuj środowisko tensorflow

source activate hello-tf

Krok 2) Usuń scikit Lean za pomocą polecenia conda

conda remove scikit-learn

Krok 3) Zainstaluj wersję deweloperską.
Zainstaluj wersję deweloperską scikit Learn wraz z niezbędnymi bibliotekami.

conda install -c anaconda git
pip install Cython
pip install h5py
pip install git+git://github.com/scikit-learn/scikit-learn.git

UWAGA: Windows użytkownik będzie musiał zainstalować Microsoft Wizualny C++ 14. Możesz to zdobyć tutaj

Przykład Scikit-Learn z uczeniem maszynowym

Ten samouczek Scikit jest podzielony na dwie części:

  1. Uczenie maszynowe za pomocą scikit-learn
  2. Jak zaufać swojemu modelowi z LIME

W pierwszej części szczegółowo opisano, jak zbudować potok, stworzyć model i dostroić hiperparametry, natomiast w drugiej części przedstawiono najnowocześniejsze rozwiązania w zakresie wyboru modelu.

Krok 1) Zaimportuj dane

Podczas tego samouczka do nauki Scikit będziesz korzystać ze zbioru danych dla dorosłych.

Aby zapoznać się z tłem tego zbioru danych, zobacz. Jeśli chcesz dowiedzieć się więcej na temat statystyk opisowych, skorzystaj z narzędzi Dive i Przegląd.

Odnosić się ten poradnik dowiedz się więcej o nurkowaniu i przeglądzie

Importujesz zbiór danych za pomocą Pand. Pamiętaj, że musisz przekonwertować typ zmiennych ciągłych na format zmiennoprzecinkowy.

Ten zbiór danych zawiera osiem zmiennych kategorycznych:

Zmienne kategoryczne są wymienione w CATE_FEATURES

  • klasa pracy
  • Edukacja
  • małżeński
  • zawód
  • związek
  • wyścig
  • seks
  • ojczyźnie

ponadto sześć zmiennych ciągłych:

Zmienne ciągłe są wymienione w CONTI_FEATURES

  • wiek
  • fnlwgt
  • edukacja_num
  • zysk kapitałowy
  • strata_kapitału
  • godziny_tydzień

Pamiętaj, że listę wypełniamy ręcznie, abyś miał lepszy pogląd, jakich kolumn używamy. Szybszym sposobem skonstruowania listy kategorialnej lub ciągłej jest użycie:

## List Categorical
CATE_FEATURES = df_train.iloc[:,:-1].select_dtypes('object').columns
print(CATE_FEATURES)

## List continuous
CONTI_FEATURES =  df_train._get_numeric_data()
print(CONTI_FEATURES)

Oto kod do importowania danych:

# Import dataset
import pandas as pd

## Define path data
COLUMNS = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital',
           'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss',
           'hours_week', 'native_country', 'label']
### Define continuous list
CONTI_FEATURES  = ['age', 'fnlwgt','capital_gain', 'education_num', 'capital_loss', 'hours_week']
### Define categorical list
CATE_FEATURES = ['workclass', 'education', 'marital', 'occupation', 'relationship', 'race', 'sex', 'native_country']

## Prepare the data
features = ['age','workclass', 'fnlwgt', 'education', 'education_num', 'marital',
           'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss',
           'hours_week', 'native_country']

PATH = "https://archive.ics.uci.edu/ml/machine-learning-databases/adult/adult.data"

df_train = pd.read_csv(PATH, skipinitialspace=True, names = COLUMNS, index_col=False)
df_train[CONTI_FEATURES] =df_train[CONTI_FEATURES].astype('float64')
df_train.describe()
wiek fnlwgt edukacja_num zysk kapitałowy strata_kapitału godziny_tydzień
liczyć 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
oznaczać 38.581647 1.897784e + 05 10.080679 1077.648844 87.303830 40.437456
std 13.640433 1.055500e + 05 2.572720 7385.292085 402.960219 12.347429
min 17.000000 1.228500e + 04 1.000000 0.000000 0.000000 1.000000
25% 28.000000 1.178270e + 05 9.000000 0.000000 0.000000 40.000000
50% 37.000000 1.783560e + 05 10.000000 0.000000 0.000000 40.000000
75% 48.000000 2.370510e + 05 12.000000 0.000000 0.000000 45.000000
max 90.000000 1.484705e + 06 16.000000 99999.000000 4356.000000 99.000000

Możesz sprawdzić liczbę unikalnych wartości funkcji native_country. Widać, że tylko jedno gospodarstwo pochodzi z Holandii-Holandii. To gospodarstwo domowe nie przekaże nam żadnych informacji, ale wyświetli błąd podczas szkolenia.

df_train.native_country.value_counts()
United-States                 29170
Mexico                          643
?                               583
Philippines                     198
Germany                         137
Canada                          121
Puerto-Rico                     114
El-Salvador                     106
India                           100
Cuba                             95
England                          90
Jamaica                          81
South                            80
China                            75
Italy                            73
Dominican-Republic               70
Vietnam                          67
Guatemala                        64
Japan                            62
Poland                           60
Columbia                         59
Taiwan                           51
Haiti                            44
Iran                             43
Portugal                         37
Nicaragua                        34
Peru                             31
France                           29
Greece                           29
Ecuador                          28
Ireland                          24
Hong                             20
Cambodia                         19
Trinadad&Tobago                  19
Thailand                         18
Laos                             18
Yugoslavia                       16
Outlying-US(Guam-USVI-etc)       14
Honduras                         13
Hungary                          13
Scotland                         12
Holand-Netherlands                1
Name: native_country, dtype: int64

Możesz wykluczyć ten pozbawiony informacji wiersz ze zbioru danych

## Drop Netherland, because only one row
df_train = df_train[df_train.native_country != "Holand-Netherlands"]

Następnie przechowujesz położenie obiektów ciągłych na liście. Będziesz go potrzebować w następnym kroku do zbudowania rurociągu.

Poniższy kod wykona pętlę po nazwach wszystkich kolumn w CONTI_FEATURES i pobierze jej lokalizację (tj. numer), a następnie dołączy ją do listy o nazwie conti_features

## Get the column index of the categorical features
conti_features = []
for i in CONTI_FEATURES:
    position = df_train.columns.get_loc(i)
    conti_features.append(position)
print(conti_features)  
[0, 2, 10, 4, 11, 12]

Poniższy kod wykonuje to samo zadanie co powyżej, ale dla zmiennej kategorycznej. Poniższy kod powtarza to, co zrobiłeś wcześniej, z wyjątkiem funkcji kategorycznych.

## Get the column index of the categorical features
categorical_features = []
for i in CATE_FEATURES:
    position = df_train.columns.get_loc(i)
    categorical_features.append(position)
print(categorical_features)  
[1, 3, 5, 6, 7, 8, 9, 13]

Możesz rzucić okiem na zbiór danych. Należy pamiętać, że każda cecha kategoryczna jest ciągiem znaków. Nie można podać modelu wartości ciągu. Musisz przekształcić zbiór danych za pomocą zmiennej fikcyjnej.

df_train.head(5)

W rzeczywistości musisz utworzyć jedną kolumnę dla każdej grupy w obiekcie. Najpierw możesz uruchomić poniższy kod, aby obliczyć całkowitą liczbę potrzebnych kolumn.

print(df_train[CATE_FEATURES].nunique(),
      'There are',sum(df_train[CATE_FEATURES].nunique()), 'groups in the whole dataset')
workclass          9
education         16
marital            7
occupation        15
relationship       6
race               5
sex                2
native_country    41
dtype: int64 There are 101 groups in the whole dataset

Cały zestaw danych zawiera 101 grup, jak pokazano powyżej. Na przykład cechy klasy roboczej mają dziewięć grup. Możesz zwizualizować nazwy grup za pomocą następujących kodów

Unique() zwraca unikalne wartości cech kategorycznych.

for i in CATE_FEATURES:
    print(df_train[i].unique())
['State-gov' 'Self-emp-not-inc' 'Private' 'Federal-gov' 'Local-gov' '?'
 'Self-emp-inc' 'Without-pay' 'Never-worked']
['Bachelors' 'HS-grad' '11th' 'Masters' '9th' 'Some-college' 'Assoc-acdm'
 'Assoc-voc' '7th-8th' 'Doctorate' 'Prof-school' '5th-6th' '10th'
 '1st-4th' 'Preschool' '12th']
['Never-married' 'Married-civ-spouse' 'Divorced' 'Married-spouse-absent'
 'Separated' 'Married-AF-spouse' 'Widowed']
['Adm-clerical' 'Exec-managerial' 'Handlers-cleaners' 'Prof-specialty'
 'Other-service' 'Sales' 'Craft-repair' 'Transport-moving'
 'Farming-fishing' 'Machine-op-inspct' 'Tech-support' '?'
 'Protective-serv' 'Armed-Forces' 'Priv-house-serv']
['Not-in-family' 'Husband' 'Wife' 'Own-child' 'Unmarried' 'Other-relative']
['White' 'Black' 'Asian-Pac-Islander' 'Amer-Indian-Eskimo' 'Other']
['Male' 'Female']
['United-States' 'Cuba' 'Jamaica' 'India' '?' 'Mexico' 'South'
 'Puerto-Rico' 'Honduras' 'England' 'Canada' 'Germany' 'Iran'
 'Philippines' 'Italy' 'Poland' 'Columbia' 'Cambodia' 'Thailand' 'Ecuador'
 'Laos' 'Taiwan' 'Haiti' 'Portugal' 'Dominican-Republic' 'El-Salvador'
 'France' 'Guatemala' 'China' 'Japan' 'Yugoslavia' 'Peru'
 'Outlying-US(Guam-USVI-etc)' 'Scotland' 'Trinadad&Tobago' 'Greece'
 'Nicaragua' 'Vietnam' 'Hong' 'Ireland' 'Hungary']

Dlatego zbiór danych szkoleniowych będzie zawierał 101 + 7 kolumn. Ostatnie siedem kolumn to cechy ciągłe.

Scikit-learn może zająć się konwersją. Odbywa się to w dwóch etapach:

  • Najpierw musisz przekonwertować ciąg na identyfikator. Na przykład władza stanowa będzie miała identyfikator 1, Self-emp-not-inc ID 2 i tak dalej. Funkcja LabelEncoder zrobi to za Ciebie
  • Transponuj każdy identyfikator do nowej kolumny. Jak wspomniano wcześniej, zbiór danych ma 101 identyfikatorów grup. Dlatego będzie 101 kolumn obejmujących wszystkie grupy cech kategorycznych. Scikit-learn ma funkcję OneHotEncoder, która wykonuje tę operację.

Krok 2) Utwórz zestaw pociągowy/testowy

Teraz, gdy zbiór danych jest gotowy, możemy go podzielić 80/20.

80 procent dla zestawu szkoleniowego i 20 procent dla zestawu testowego.

Możesz użyć train_test_split. Pierwszym argumentem jest ramka danych zawierająca funkcje, a drugim argumentem jest ramka danych etykiety. Możesz określić rozmiar zestawu testowego za pomocą test_size.

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(df_train[features],
                                                    df_train.label,
                                                    test_size = 0.2,
                                                    random_state=0)
X_train.head(5)
print(X_train.shape, X_test.shape)
(26048, 14) (6512, 14)

Krok 3) Zbuduj rurociąg

Potok ułatwia zasilanie modelu spójnymi danymi.

Pomysł polega na umieszczeniu surowych danych w „kanale” w celu wykonania operacji.

Na przykład, w przypadku bieżącego zestawu danych, musisz standaryzować zmienne ciągłe i konwertować dane kategoryczne. Zauważ, że możesz wykonać dowolną operację wewnątrz potoku. Na przykład, jeśli masz „NA” w zestawie danych, możesz je zastąpić średnią lub medianą. Możesz również tworzyć nowe zmienne.

Masz wybór; zakoduj na stałe dwa procesy lub utwórz potok. Pierwszy wybór może z czasem prowadzić do wycieku danych i powstania niespójności. Lepszą opcją jest użycie rurociągu.

from sklearn.preprocessing import StandardScaler, OneHotEncoder, LabelEncoder
from sklearn.compose import ColumnTransformer, make_column_transformer
from sklearn.pipeline import make_pipeline
from sklearn.linear_model import LogisticRegression

Przed przekazaniem danych do klasyfikatora logistycznego rurociąg wykona dwie operacje:

  1. Standaryzuj zmienną: `StandardScaler()“
  2. Konwertuj cechy kategoryczne: OneHotEncoder(sparse=False)

Możesz wykonać dwa kroki, używając make_column_transformer. Ta funkcja nie jest dostępna w aktualnej wersji scikit-learn (0.19). W obecnej wersji nie jest możliwe wykonanie kodera etykiet i jednego kodera na gorąco w potoku. To jeden z powodów, dla których zdecydowaliśmy się użyć wersji deweloperskiej.

make_column_transformer jest łatwy w użyciu. Musisz zdefiniować, które kolumny zastosować transformację i jaką transformację wykonać. Na przykład, aby ujednolicić funkcję ciągłą, możesz zrobić:

  • conti_features, StandardScaler() wewnątrz make_column_transformer.
    • conti_features: lista ze zmienną ciągłą
    • StandardScaler: standaryzuj zmienną

Obiekt OneHotEncoder wewnątrz make_column_transformer automatycznie koduje etykietę.

preprocess = make_column_transformer(
    (conti_features, StandardScaler()),
    ### Need to be numeric not string to specify columns name 
    (categorical_features, OneHotEncoder(sparse=False))
)

Możesz sprawdzić, czy potok działa z fit_transform. Zestaw danych powinien mieć następujący kształt: 26048, 107

preprocess.fit_transform(X_train).shape
(26048, 107)

Transformator danych jest gotowy do użycia. Możesz utworzyć potok za pomocą make_pipeline. Po przekształceniu danych można wprowadzić regresję logistyczną.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Trenowanie modelu za pomocą scikit-learn jest trywialne. Należy zastosować dopasowanie obiektu poprzedzone potokiem, czyli model. Możesz wydrukować dokładność za pomocą obiektu score z biblioteki scikit-learn

model.fit(X_train, y_train)
print("logistic regression score: %f" % model.score(X_test, y_test))
logistic regression score: 0.850891

Wreszcie możesz przewidzieć klasy za pomocą przewidywania_proba. Zwraca prawdopodobieństwo dla każdej klasy. Zauważ, że sumuje się do jednego.

model.predict_proba(X_test)
array([[0.83576663, 0.16423337],
       [0.94582765, 0.05417235],
       [0.64760587, 0.35239413],
       ...,
       [0.99639252, 0.00360748],
       [0.02072181, 0.97927819],
       [0.56781353, 0.43218647]])

Krok 4) Korzystanie z naszego potoku w wyszukiwaniu siatki

Dostrajanie hiperparametrów (zmiennych określających strukturę sieci, takich jak jednostki ukryte) może być żmudne i wyczerpujące.

Jednym ze sposobów oceny modelu może być zmiana rozmiaru zbioru uczącego i ocena jego wydajności.

Możesz powtórzyć tę metodę dziesięć razy, aby zobaczyć metryki wyniku. Jest to jednak za dużo pracy.

Zamiast tego scikit-learn udostępnia funkcję dostrajania parametrów i sprawdzania poprawności krzyżowej.

Walidacja krzyżowa

Walidacja krzyżowa oznacza, że ​​podczas treningu zbiór treningowy jest przesuwany n razy w składach, a następnie oceniany jest model n razy. Na przykład, jeśli cv jest ustawione na 10, zbiór uczący jest szkolony i oceniany dziesięć razy. W każdej rundzie klasyfikator wybiera losowo dziewięć fałd do trenowania modelu, a dziesiąta część jest przeznaczona do oceny.

Wyszukiwanie w siatce

Każdy klasyfikator ma hiperparametry do dostrojenia. Możesz wypróbować różne wartości lub ustawić siatkę parametrów. Jeśli wejdziesz na oficjalną stronę scikit-learn, zobaczysz, że klasyfikator logistyczny ma inne parametry do dostrojenia. Aby przyspieszyć trening, wybierasz dostrojenie parametru C. Kontroluje parametr regularyzacji. Powinno być pozytywne. Mała wartość nadaje większą wagę regulatorowi.

Możesz użyć obiektu GridSearchCV. Aby dostroić, musisz utworzyć słownik zawierający hiperparametry.

Podajesz hiperparametry, a następnie wartości, które chcesz wypróbować. Na przykład, aby dostroić parametr C, użyj:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: Parametr jest poprzedzony małą literą nazwy klasyfikatora i dwoma podkreśleniami.

Model wypróbuje cztery różne wartości: 0.001, 0.01, 0.1 i 1.

Trenujesz model za pomocą 10 fałd: cv=10

from sklearn.model_selection import GridSearchCV
# Construct the parameter grid
param_grid = {
    'logisticregression__C': [0.001, 0.01,0.1, 1.0],
    }

Model można trenować za pomocą GridSearchCV z parametrami gri i cv.

# Train the model
grid_clf = GridSearchCV(model,
                        param_grid,
                        cv=10,
                        iid=False)
grid_clf.fit(X_train, y_train)

WYDAJNOŚĆ

GridSearchCV(cv=10, error_score='raise-deprecating',
       estimator=Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...ty='l2', random_state=None, solver='liblinear', tol=0.0001,
          verbose=0, warm_start=False))]),
       fit_params=None, iid=False, n_jobs=1,
       param_grid={'logisticregression__C': [0.001, 0.01, 0.1, 1.0]},
       pre_dispatch='2*n_jobs', refit=True, return_train_score='warn',
       scoring=None, verbose=0)

Aby uzyskać dostęp do najlepszych parametrów, użyj best_params_

grid_clf.best_params_

WYDAJNOŚĆ

{'logisticregression__C': 1.0}

Po przeszkoleniu modelu z czterema różnymi wartościami regularyzacji optymalnym parametrem jest

print("best logistic regression from grid search: %f" % grid_clf.best_estimator_.score(X_test, y_test))

najlepsza regresja logistyczna z wyszukiwania w siatce: 0.850891

Aby uzyskać dostęp do przewidywanych prawdopodobieństw:

grid_clf.best_estimator_.predict_proba(X_test)
array([[0.83576677, 0.16423323],
       [0.9458291 , 0.0541709 ],
       [0.64760416, 0.35239584],
       ...,
       [0.99639224, 0.00360776],
       [0.02072033, 0.97927967],
       [0.56782222, 0.43217778]])

Model XGBoost z nauką scikit

Wypróbujmy przykłady Scikit-learn, aby wytrenować jeden z najlepszych klasyfikatorów na rynku. XGBoost to ulepszenie w stosunku do losowego lasu. Podstawa teoretyczna klasyfikatora poza zakresem tego zagadnienia Python Poradnik Scikita. Pamiętaj, że XGBoost wygrał wiele konkursów kaggle. Przy średnim rozmiarze zbioru danych może działać równie dobrze, jak algorytm głębokiego uczenia się, a nawet lepiej.

Klasyfikator jest trudny do wyszkolenia, ponieważ ma dużą liczbę parametrów do dostrojenia. Możesz oczywiście użyć GridSearchCV, aby wybrać parametr za siebie.

Zamiast tego zobaczmy, jak zastosować lepszy sposób na znalezienie optymalnych parametrów. Uczenie GridSearchCV może być żmudne i bardzo długie, jeśli przekażesz wiele wartości. Przestrzeń poszukiwań rośnie wraz z liczbą parametrów. Preferowanym rozwiązaniem jest użycie RandomizedSearchCV. Metoda ta polega na losowym wyborze wartości każdego hiperparametru po każdej iteracji. Na przykład, jeśli klasyfikator jest szkolony w ciągu 1000 iteracji, ocenianych jest 1000 kombinacji. Działa to mniej więcej tak. GridSearchCV

Musisz zaimportować xgboost. Jeśli biblioteka nie jest zainstalowana, użyj pip3 install xgboost lub

use import sys
!{sys.executable} -m pip install xgboost

In Jupyter środowisko

Następnie

import xgboost
from sklearn.model_selection import RandomizedSearchCV
from sklearn.model_selection import StratifiedKFold

Następny krok w tym Scikicie Python samouczek obejmuje określenie parametrów do dostrojenia. Możesz zapoznać się z oficjalną dokumentacją, aby zobaczyć wszystkie parametry do dostrojenia. Ze względu na Python Sklearn, wybierasz tylko dwa hiperparametry z dwiema wartościami każdy. Uczenie XGBoost zajmuje dużo czasu, im więcej hiperparametrów w siatce, tym dłużej trzeba czekać.

params = {
        'xgbclassifier__gamma': [0.5, 1],
        'xgbclassifier__max_depth': [3, 4]
        }

Konstruujesz nowy potok z klasyfikatorem XGBoost. Wybierasz zdefiniowanie 600 estymatorów. Zauważ, że n_estimators to parametr, który możesz dostroić. Wysoka wartość może prowadzić do nadmiernego dopasowania. Możesz samodzielnie wypróbować różne wartości, ale pamiętaj, że może to zająć godziny. Używasz wartości domyślnej dla innych parametrów

model_xgb = make_pipeline(
    preprocess,
    xgboost.XGBClassifier(
                          n_estimators=600,
                          objective='binary:logistic',
                          silent=True,
                          nthread=1)
)

Możesz ulepszyć weryfikację krzyżową za pomocą walidatora krzyżowego Stratified K-Folds. Konstruujesz tutaj tylko trzy zagięcia, aby przyspieszyć obliczenia, ale obniżyć jakość. Aby poprawić wyniki, w domu zwiększ tę wartość do 5 lub 10.

Decydujesz się na uczenie modelu w czterech iteracjach.

skf = StratifiedKFold(n_splits=3,
                      shuffle = True,
                      random_state = 1001)

random_search = RandomizedSearchCV(model_xgb,
                                   param_distributions=params,
                                   n_iter=4,
                                   scoring='accuracy',
                                   n_jobs=4,
                                   cv=skf.split(X_train, y_train),
                                   verbose=3,
                                   random_state=1001)

Randomizowane wyszukiwanie jest gotowe do użycia, możesz wytrenować model

#grid_xgb = GridSearchCV(model_xgb, params, cv=10, iid=False)
random_search.fit(X_train, y_train)
Fitting 3 folds for each of 4 candidates, totalling 12 fits
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8759645283888057, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8729701715996775, total= 1.0min
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=0.5, score=0.8706519235199263, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5 ............
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8735460094437406, total= 1.3min
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8722791661868018, total=  57.7s
[CV] xgbclassifier__max_depth=3, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8753886905447426, total= 1.0min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8697304768486523, total= 1.3min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=0.5, score=0.8740066797189912, total= 1.4min
[CV] xgbclassifier__max_depth=4, xgbclassifier__gamma=1 ..............
[CV]  xgbclassifier__max_depth=3, xgbclassifier__gamma=1, score=0.8707671043538355, total= 1.0min
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8729701715996775, total= 1.2min
[Parallel(n_jobs=4)]: Done  10 out of  12 | elapsed:  3.6min remaining:   43.5s
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8736611770125533, total= 1.2min
[CV]  xgbclassifier__max_depth=4, xgbclassifier__gamma=1, score=0.8692697535130154, total= 1.2min
[Parallel(n_jobs=4)]: Done  12 out of  12 | elapsed:  3.6min finished
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/model_selection/_search.py:737: DeprecationWarning: The default of the `iid` parameter will change from True to False in version 0.22 and will be removed in 0.24. This will change numeric results when test-set sizes are unequal. DeprecationWarning)
RandomizedSearchCV(cv=<generator object _BaseKFold.split at 0x1101eb830>,
          error_score='raise-deprecating',
          estimator=Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...
       reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
       silent=True, subsample=1))]),
          fit_params=None, iid='warn', n_iter=4, n_jobs=4,
          param_distributions={'xgbclassifier__gamma': [0.5, 1], 'xgbclassifier__max_depth': [3, 4]},
          pre_dispatch='2*n_jobs', random_state=1001, refit=True,
          return_train_score='warn', scoring='accuracy', verbose=3)

Jak widać, XGBoost ma lepszy wynik niż poprzednia regresja logistyczna.

print("Best parameter", random_search.best_params_)
print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
Best parameter {'xgbclassifier__max_depth': 3, 'xgbclassifier__gamma': 0.5}
best logistic regression from grid search: 0.873157
random_search.best_estimator_.predict(X_test)
array(['<=50K', '<=50K', '<=50K', ..., '<=50K', '>50K', '<=50K'],      dtype=object)

Utwórz DNN za pomocą MLPClassifier w scikit-learn

Wreszcie możesz wytrenować algorytm głębokiego uczenia się za pomocą scikit-learn. Metoda jest taka sama jak w przypadku drugiego klasyfikatora. Klasyfikator jest dostępny na stronie MLPClassifier.

from sklearn.neural_network import MLPClassifier

Definiujesz następujący algorytm głębokiego uczenia:

  • Adam Rozwiązujący
  • Funkcja aktywacji Relu
  • Alfa = 0.0001
  • wielkość partii 150 szt
  • Dwie ukryte warstwy zawierające odpowiednio 100 i 50 neuronów
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Możesz zmienić liczbę warstw, aby ulepszyć model

model_dnn.fit(X_train, y_train)
  print("DNN regression score: %f" % model_dnn.score(X_test, y_test))

Wynik regresji DNN: 0.821253

LIME: Zaufaj swojemu modelowi

Teraz, gdy masz dobry model, potrzebujesz narzędzia, które mu zaufa. Nauczanie maszynowe Algorytm, zwłaszcza losowy las i sieć neuronowa, są znane jako algorytmy czarnej skrzynki. Inaczej mówiąc, działa, ale nikt nie wie dlaczego.

Trzej badacze wymyślili świetne narzędzie umożliwiające sprawdzenie, w jaki sposób komputer dokonuje przewidywań. Artykuł nosi tytuł Dlaczego powinienem ci ufać?

Opracowali algorytm o nazwie Lokalne interpretowalne objaśnienia niezależne od modelu (LIME).

Brać przykład:

czasami nie wiesz, czy możesz ufać przewidywaniom uczenia maszynowego:

Na przykład lekarz nie może ufać diagnozie tylko dlatego, że tak powiedział komputer. Musisz także wiedzieć, czy możesz zaufać modelowi przed wprowadzeniem go do produkcji.

Wyobraź sobie, że możemy zrozumieć, dlaczego dowolny klasyfikator prognozuje nawet niezwykle skomplikowane modele, takie jak sieci neuronowe, losowe lasy lub svm z dowolnym jądrem

łatwiej będzie zaufać przewidywaniom, jeśli zrozumiemy ich przyczyny. Na przykładzie lekarza, jeśli model powiedziałby mu, jakie objawy są istotne, można mu zaufać, łatwiej jest też zorientować się, czy nie należy ufać modelowi.

Lime może powiedzieć, jakie cechy wpływają na decyzje klasyfikatora

Przygotowywanie danych

Jest to kilka rzeczy, które musisz zmienić, aby uruchomić LIME pyton. Przede wszystkim musisz zainstalować lime w terminalu. Możesz użyć pip install lime

Lime wykorzystuje obiekt LimeTabularExplainer do lokalnego przybliżenia modelu. Ten obiekt wymaga:

  • zbiór danych w formacie numpy
  • Nazwa funkcji: nazwy_funkcji
  • Nazwa klas: nazwy_klas
  • Indeks kolumny cech kategorycznych: categorical_features
  • Nazwa grupy dla każdej cechy kategorycznej: nazwy_kategorii

Utwórz numpy zestaw pociągów

Możesz skopiować i przekonwertować df_train z pand na tępy bardzo łatwo

df_train.head(5)
# Create numpy data
df_lime = df_train
df_lime.head(3)

Uzyskaj nazwę klasy Etykieta jest dostępna za pomocą obiektu unikatowego(). Powinieneś zobaczyć:

  • „<= 50 tys.”
  • „> 50 tys.”
# Get the class name
class_names = df_lime.label.unique()
class_names
array(['<=50K', '>50K'], dtype=object)

indeks kolumny cech kategorycznych

Możesz użyć metody, którą pochyliłeś się wcześniej, aby uzyskać nazwę grupy. Kodujesz etykietę za pomocą LabelEncoder. Powtarzasz operację na wszystkich cechach kategorycznych.

## 
import sklearn.preprocessing as preprocessing
categorical_names = {}
for feature in CATE_FEATURES:
    le = preprocessing.LabelEncoder()
    le.fit(df_lime[feature])
    df_lime[feature] = le.transform(df_lime[feature])
    categorical_names[feature] = le.classes_
print(categorical_names)    
{'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private',
       'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'],
      dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th',
       'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad',
       'Masters', 'Preschool', 'Prof-school', 'Some-college'],
      dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse',
       'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'],
      dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair',
       'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners',
       'Machine-op-inspct', 'Other-service', 'Priv-house-serv',
       'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support',
       'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child',
       'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other',
       'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba',
       'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England',
       'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras',
       'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica',
       'Japan', 'Laos', 'Mexico', 'Nicaragua',
       'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland',
       'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan',
       'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam',
       'Yugoslavia'], dtype=object)}

df_lime.dtypes
age               float64
workclass           int64
fnlwgt            float64
education           int64
education_num     float64
marital             int64
occupation          int64
relationship        int64
race                int64
sex                 int64
capital_gain      float64
capital_loss      float64
hours_week        float64
native_country      int64
label              object
dtype: object

Teraz, gdy zbiór danych jest gotowy, możesz skonstruować inny zbiór danych, jak pokazano w poniższych przykładach nauki Scikit. W rzeczywistości przekształcasz dane poza potokiem, aby uniknąć błędów w LIME. Zestaw szkoleniowy w LimeTabularExplainer powinien być tablicą numpy bez łańcucha. Dzięki powyższej metodzie masz już przekonwertowany zestaw danych szkoleniowych.

from sklearn.model_selection import train_test_split
X_train_lime, X_test_lime, y_train_lime, y_test_lime = train_test_split(df_lime[features],
                                                    df_lime.label,
                                                    test_size = 0.2,
                                                    random_state=0)
X_train_lime.head(5)

Możesz stworzyć potok o optymalnych parametrach z XGBoost

model_xgb = make_pipeline(
    preprocess,
    xgboost.XGBClassifier(max_depth = 3,
                          gamma = 0.5,
                          n_estimators=600,
                          objective='binary:logistic',
                          silent=True,
                          nthread=1))

model_xgb.fit(X_train_lime, y_train_lime)
/Users/Thomas/anaconda3/envs/hello-tf/lib/python3.6/site-packages/sklearn/preprocessing/_encoders.py:351: FutureWarning: The handling of integer data will change in version 0.22. Currently, the categories are determined based on the range [0, max(values)], while in the future they will be determined based on the unique values.
If you want the future behavior and silence this warning, you can specify "categories='auto'."In case you used a LabelEncoder before this OneHotEncoder to convert the categories to integers, then you can now use the OneHotEncoder directly.
  warnings.warn(msg, FutureWarning)
Pipeline(memory=None,
     steps=[('columntransformer', ColumnTransformer(n_jobs=1, remainder='drop', transformer_weights=None,
         transformers=[('standardscaler', StandardScaler(copy=True, with_mean=True, with_std=True), [0, 2, 10, 4, 11, 12]), ('onehotencoder', OneHotEncoder(categorical_features=None, categories=None,...
       reg_alpha=0, reg_lambda=1, scale_pos_weight=1, seed=None,
       silent=True, subsample=1))])

Otrzymujesz ostrzeżenie. Ostrzeżenie wyjaśnia, że ​​nie musisz tworzyć enkodera etykiet przed potokiem. Jeśli nie chcesz używać LIME, możesz użyć metody z pierwszej części samouczka Machine Learning with Scikit-learn. W przeciwnym razie możesz pozostać przy tej metodzie, najpierw utwórz zakodowany zestaw danych, ustaw koder get the hot one w potoku.

print("best logistic regression from grid search: %f" % model_xgb.score(X_test_lime, y_test_lime))
best logistic regression from grid search: 0.873157
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01],
       [9.5173013e-01, 4.8269872e-02],
       [7.9344827e-01, 2.0655173e-01],
       ...,
       [9.9031430e-01, 9.6856682e-03],
       [6.4581633e-04, 9.9935418e-01],
       [9.7104281e-01, 2.8957171e-02]], dtype=float32)

Zanim użyjemy LIME w akcji, utwórzmy tablicę numpy z cechami niewłaściwej klasyfikacji. Możesz użyć tej listy później, aby dowiedzieć się, co wprowadziło klasyfikator w błąd.

temp = pd.concat([X_test_lime, y_test_lime], axis= 1)
temp['predicted'] = model_xgb.predict(X_test_lime)
temp['wrong']=  temp['label'] != temp['predicted']
temp = temp.query('wrong==True').drop('wrong', axis=1)
temp= temp.sort_values(by=['label'])
temp.shape

(826, 16)

Tworzysz funkcję lambda, aby pobrać prognozę z modelu przy użyciu nowych danych. Będziesz go wkrótce potrzebować.

predict_fn = lambda x: model_xgb.predict_proba(x).astype(float)
X_test_lime.dtypes
age               float64
workclass           int64
fnlwgt            float64
education           int64
education_num     float64
marital             int64
occupation          int64
relationship        int64
race                int64
sex                 int64
capital_gain      float64
capital_loss      float64
hours_week        float64
native_country      int64
dtype: object
predict_fn(X_test_lime)
array([[7.96461046e-01, 2.03538969e-01],
       [9.51730132e-01, 4.82698716e-02],
       [7.93448269e-01, 2.06551731e-01],
       ...,
       [9.90314305e-01, 9.68566816e-03],
       [6.45816326e-04, 9.99354184e-01],
       [9.71042812e-01, 2.89571714e-02]])

Konwertujesz ramkę danych pand na tablicę numpy

X_train_lime = X_train_lime.values
X_test_lime = X_test_lime.values
X_test_lime
array([[4.00000e+01, 5.00000e+00, 1.93524e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       [2.70000e+01, 4.00000e+00, 2.16481e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       [2.50000e+01, 4.00000e+00, 2.56263e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01],
       ...,
       [2.80000e+01, 6.00000e+00, 2.11032e+05, ..., 0.00000e+00,
        4.00000e+01, 2.50000e+01],
       [4.40000e+01, 4.00000e+00, 1.67005e+05, ..., 0.00000e+00,
        6.00000e+01, 3.80000e+01],
       [5.30000e+01, 4.00000e+00, 2.57940e+05, ..., 0.00000e+00,
        4.00000e+01, 3.80000e+01]])
model_xgb.predict_proba(X_test_lime)
array([[7.9646105e-01, 2.0353897e-01],
       [9.5173013e-01, 4.8269872e-02],
       [7.9344827e-01, 2.0655173e-01],
       ...,
       [9.9031430e-01, 9.6856682e-03],
       [6.4581633e-04, 9.9935418e-01],
       [9.7104281e-01, 2.8957171e-02]], dtype=float32)
print(features,
      class_names,
      categorical_features,
      categorical_names)
['age', 'workclass', 'fnlwgt', 'education', 'education_num', 'marital', 'occupation', 'relationship', 'race', 'sex', 'capital_gain', 'capital_loss', 'hours_week', 'native_country'] ['<=50K' '>50K'] [1, 3, 5, 6, 7, 8, 9, 13] {'workclass': array(['?', 'Federal-gov', 'Local-gov', 'Never-worked', 'Private',
       'Self-emp-inc', 'Self-emp-not-inc', 'State-gov', 'Without-pay'],
      dtype=object), 'education': array(['10th', '11th', '12th', '1st-4th', '5th-6th', '7th-8th', '9th',
       'Assoc-acdm', 'Assoc-voc', 'Bachelors', 'Doctorate', 'HS-grad',
       'Masters', 'Preschool', 'Prof-school', 'Some-college'],
      dtype=object), 'marital': array(['Divorced', 'Married-AF-spouse', 'Married-civ-spouse',
       'Married-spouse-absent', 'Never-married', 'Separated', 'Widowed'],
      dtype=object), 'occupation': array(['?', 'Adm-clerical', 'Armed-Forces', 'Craft-repair',
       'Exec-managerial', 'Farming-fishing', 'Handlers-cleaners',
       'Machine-op-inspct', 'Other-service', 'Priv-house-serv',
       'Prof-specialty', 'Protective-serv', 'Sales', 'Tech-support',
       'Transport-moving'], dtype=object), 'relationship': array(['Husband', 'Not-in-family', 'Other-relative', 'Own-child',
       'Unmarried', 'Wife'], dtype=object), 'race': array(['Amer-Indian-Eskimo', 'Asian-Pac-Islander', 'Black', 'Other',
       'White'], dtype=object), 'sex': array(['Female', 'Male'], dtype=object), 'native_country': array(['?', 'Cambodia', 'Canada', 'China', 'Columbia', 'Cuba',
       'Dominican-Republic', 'Ecuador', 'El-Salvador', 'England',
       'France', 'Germany', 'Greece', 'Guatemala', 'Haiti', 'Honduras',
       'Hong', 'Hungary', 'India', 'Iran', 'Ireland', 'Italy', 'Jamaica',
       'Japan', 'Laos', 'Mexico', 'Nicaragua',
       'Outlying-US(Guam-USVI-etc)', 'Peru', 'Philippines', 'Poland',
       'Portugal', 'Puerto-Rico', 'Scotland', 'South', 'Taiwan',
       'Thailand', 'Trinadad&Tobago', 'United-States', 'Vietnam',
       'Yugoslavia'], dtype=object)}
import lime
import lime.lime_tabular
### Train should be label encoded not one hot encoded
explainer = lime.lime_tabular.LimeTabularExplainer(X_train_lime ,
                                                   feature_names = features,
                                                   class_names=class_names,
                                                   categorical_features=categorical_features, 
                                                   categorical_names=categorical_names,
                                                   kernel_width=3)

Wybierzmy losowe gospodarstwo domowe ze zbioru testowego i zobaczmy przewidywania modelu oraz sposób, w jaki komputer dokonał swojego wyboru.

import numpy as np
np.random.seed(1)
i = 100
print(y_test_lime.iloc[i])
>50K
X_test_lime[i]
array([4.20000e+01, 4.00000e+00, 1.76286e+05, 7.00000e+00, 1.20000e+01,
       2.00000e+00, 4.00000e+00, 0.00000e+00, 4.00000e+00, 1.00000e+00,
       0.00000e+00, 0.00000e+00, 4.00000e+01, 3.80000e+01])

Możesz użyć wyjaśniacza z wyjaśnieniem_instancji, aby sprawdzić wyjaśnienie modelu

exp = explainer.explain_instance(X_test_lime[i], predict_fn, num_features=6)
exp.show_in_notebook(show_all=False)

Przygotowywanie danych

Widzimy, że klasyfikator poprawnie przewidział gospodarstwo domowe. Dochody rzeczywiście przekraczają 50 tys.

Pierwszą rzeczą, którą możemy powiedzieć, jest to, że klasyfikator nie jest tak pewny przewidywanych prawdopodobieństw. Maszyna przewiduje, że gospodarstwo domowe ma dochód powyżej 50 tys. z prawdopodobieństwem 64%. Te 64% składa się z zysku kapitałowego i małżeńskiego. Kolor niebieski przyczynia się negatywnie do klasy dodatniej, a linia pomarańczowa, pozytywnie.

Klasyfikator jest mylący, ponieważ zysk kapitałowy tego gospodarstwa domowego jest zerowy, podczas gdy zysk kapitałowy jest zwykle dobrym prognostykiem bogactwa. Poza tym gospodarstwo domowe pracuje mniej niż 40 godzin tygodniowo. Wiek, zawód i płeć mają pozytywny wpływ na klasyfikator.

Gdyby stan cywilny był wolny, klasyfikator przewidziałby dochód poniżej 50 tys. (0.64-0.18 = 0.46)

Możemy spróbować z innym gospodarstwem domowym, które zostało błędnie sklasyfikowane

temp.head(3)
temp.iloc[1,:-2]
age                  58
workclass             4
fnlwgt            68624
education            11
education_num         9
marital               2
occupation            4
relationship          0
race                  4
sex                   1
capital_gain          0
capital_loss          0
hours_week           45
native_country       38
Name: 20931, dtype: object
i = 1
print('This observation is', temp.iloc[i,-2:])
This observation is label        <=50K
predicted     >50K
Name: 20931, dtype: object
exp = explainer.explain_instance(temp.iloc[1,:-2], predict_fn, num_features=6)
exp.show_in_notebook(show_all=False)

Przygotowywanie danych

Klasyfikator przewidział dochód poniżej 50 tys., co nie jest prawdą. To gospodarstwo domowe wydaje się dziwne. Nie ma zysków kapitałowych ani strat kapitałowych. Jest rozwiedziony, ma 60 lat i jest osobą wykształconą, tj. liczba_wykształcenia > 12. Według ogólnego schematu gospodarstwo to powinno, jak wyjaśnia klasyfikator, osiągać dochody poniżej 50 tys.

Próbujesz pobawić się LIME. Zauważysz rażące błędy klasyfikatora.

Możesz sprawdzić GitHub właściciela biblioteki. Zapewniają dodatkową dokumentację do klasyfikacji obrazów i tekstu.

Podsumowanie

Poniżej znajduje się lista przydatnych poleceń w wersji scikit Learn >=0.20

utwórz zestaw danych pociągu/testu stażyści podzielili się
Zbuduj rurociąg
wybierz kolumnę i zastosuj transformację makekolumnatransformator
rodzaj transformacji
ujednolicić Skaler standardowy
minimum maksimum MinMax Skaler
Normalizować Normalizer
Przypisz brakującą wartość przypisać
Konwertuj kategoryczne JedenHotEncoder
Dopasuj i przekształć dane dopasowanie_transformacji
Zrób rurociąg make_pipeline
Model podstawowy
regresja logistyczna Regresja logistyczna
XGBoost Klasyfikator XGB
Sieć neuronowa Klasyfikator MLP
Wyszukiwanie w siatce GridSearchCV
Wyszukiwanie losowe Wyszukiwanie losoweCV