Výukový program Scikit-Learn: Jak nainstalovat a příklady Scikit-Learn

Co je to Scikit-learn?

Scikit-učit se je open-source Python knihovna pro strojové učení. Podporuje nejmodernější algoritmy, jako je KNN, XGBoost, random forest a SVM. Je postaven na vrcholu NumPy. Scikit-learn je široce používán v soutěži Kaggle i v předních technologických společnostech. Pomáhá při předzpracování, redukci rozměrů (výběr parametrů), klasifikaci, regresi, shlukování a výběru modelu.

Scikit-learn má nejlepší dokumentaci ze všech open-source knihoven. Poskytuje vám interaktivní graf na adrese https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Jak Scikit Learn funguje
Jak Scikit Learn funguje

Scikit-learn není příliš náročný na použití a poskytuje vynikající výsledky. Nicméně scikit learn nepodporuje paralelní výpočty. Je možné s ním spustit algoritmus hlubokého učení, ale není to optimální řešení, zvláště pokud víte, jak používat TensorFlow.

Jak stáhnout a nainstalovat Scikit-learn

Nyní v tomto Python Scikit-learn tutoriál, naučíme se, jak stáhnout a nainstalovat Scikit-learn:

Možnost 1: AWS

scikit-learn lze použít přes AWS. Prosím odkázat Obraz dockeru, který má předinstalovaný scikit-learn.

Chcete-li použít vývojářskou verzi, použijte příkaz in Jupyter

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

Možnost 2: Mac nebo Mac Windows pomocí Anacondy

Chcete-li se dozvědět o instalaci Anaconda, viz https://www.guru99.com/download-install-tensorflow.html

Nedávno vývojáři scikit vydali vývojovou verzi, která řeší běžný problém, kterému čelí současná verze. Zjistili jsme, že je pohodlnější používat vývojářskou verzi místo aktuální verze.

Jak nainstalovat scikit-learn s prostředím Conda

Pokud jste si nainstalovali scikit-learn s prostředím conda, postupujte podle kroků pro aktualizaci na verzi 0.20

Krok 1) Aktivujte prostředí tensorflow

source activate hello-tf

Krok 2) Odstraňte scikit lean pomocí příkazu conda

conda remove scikit-learn

Krok 3) Nainstalujte vývojářskou verzi.
Nainstalujte vývojářskou verzi scikit learn spolu s potřebnými knihovnami.

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

POZNÁMKA: Windows uživatel bude muset nainstalovat Microsoft Vizuální C++ 14. Můžete to získat od zde

Příklad Scikit-Learn se strojovým učením

Tento tutoriál Scikit je rozdělen do dvou částí:

  1. Strojové učení se scikit-learn
  2. Jak důvěřovat svému modelu s LIME

První část podrobně popisuje, jak postavit potrubí, vytvořit model a vyladit hyperparametry, zatímco druhá část poskytuje nejmodernější z hlediska výběru modelu.

Krok 1) Importujte data

Během tohoto výukového programu Scikit budete používat datovou sadu pro dospělé.

Pozadí v tomto datovém souboru naleznete v případě, že se chcete dozvědět více o popisných statistikách, použijte nástroje Dive a Overview.

Odkázat tento výukový program zjistěte více o ponoru a přehledu

Importujete datovou sadu pomocí Pandas. Všimněte si, že musíte převést typ spojitých proměnných do formátu float.

Tato datová sada obsahuje osm kategorických proměnných:

Kategorické proměnné jsou uvedeny v CATE_FEATURES

  • pracovní třída
  • vzdělání
  • manželský
  • povolání
  • vztah
  • závod
  • pohlaví
  • rodná země

navíc šest spojitých proměnných:

Spojité proměnné jsou uvedeny v CONTI_FEATURES

  • stáří
  • fnlwgt
  • vzdělání_číslo
  • kapitálový zisk
  • kapitálová_ztráta
  • hodiny_týden

Všimněte si, že seznam vyplňujeme ručně, abyste měli lepší představu o tom, jaké sloupce používáme. Rychlejší způsob, jak vytvořit seznam kategorických nebo spojitých, je použít:

## 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)

Zde je kód pro import dat:

# 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()
stáří fnlwgt vzdělání_číslo kapitálový zisk kapitálová_ztráta hodiny_týden
počítat 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
střední 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

Můžete zkontrolovat počet jedinečných hodnot funkcí native_country. Vidíte, že pouze jedna domácnost pochází z Holandska-Nizozemí. Tato domácnost nám žádné informace nepřinese, ale dojde k chybě během školení.

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

Tento neinformativní řádek můžete z datové sady vyloučit

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

Dále uložíte polohu spojitých prvků do seznamu. Budete jej potřebovat v dalším kroku pro stavbu potrubí.

Níže uvedený kód bude opakovat názvy všech sloupců v CONTI_FEATURES a získá jeho umístění (tj. jeho číslo) a poté jej připojí k seznamu s názvem 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]

Níže uvedený kód dělá stejnou práci jako výše, ale pro kategorickou proměnnou. Níže uvedený kód opakuje to, co jste udělali dříve, s výjimkou kategorických funkcí.

## 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]

Můžete se podívat na datovou sadu. Všimněte si, že každý kategorický prvek je řetězec. Model nelze napájet hodnotou řetězce. Musíte transformovat datovou sadu pomocí fiktivní proměnné.

df_train.head(5)

Ve skutečnosti musíte vytvořit jeden sloupec pro každou skupinu v prvku. Nejprve můžete spustit kód níže a vypočítat celkový počet potřebných sloupců.

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

Celá datová sada obsahuje 101 skupin, jak je uvedeno výše. Například funkce pracovní třídy mají devět skupin. Názvy skupin si můžete vizualizovat pomocí následujících kódů

unique() vrací jedinečné hodnoty kategoriálních funkcí.

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']

Tréninková datová sada tedy bude obsahovat 101 + 7 sloupců. Posledních sedm sloupců jsou souvislé prvky.

O konverzi se může postarat Scikit-learn. Provádí se ve dvou krocích:

  • Nejprve musíte převést řetězec na ID. Například stát-gov bude mít ID 1, Self-emp-not-inc ID 2 a tak dále. Funkce LabelEncoder to udělá za vás
  • Transponujte každé ID do nového sloupce. Jak již bylo zmíněno, datová sada má 101 ID skupiny. Proto zde bude 101 sloupců zachycujících všechny skupiny prvků kategorií. Scikit-learn má funkci nazvanou OneHotEncoder, která tuto operaci provádí

Krok 2) Vytvořte vlak/testovací sadu

Nyní, když je datová sada připravena, můžeme ji rozdělit v poměru 80/20.

80 procent pro tréninkovou sadu a 20 procent pro testovací sadu.

Můžete použít train_test_split. První argument je dataframe is the features a druhý argument je label dataframe. Velikost testovací sady můžete určit 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) Postavte potrubí

Potrubí usnadňuje dodávání modelu konzistentními daty.

Základní myšlenkou je umístit nezpracovaná data do „potrubí“ pro provádění operací.

Například s aktuální datovou sadou potřebujete standardizovat spojité proměnné a převést kategorická data. Všimněte si, že uvnitř potrubí můžete provádět jakoukoli operaci. Pokud například máte v sadě dat „NA“, můžete je nahradit průměrem nebo mediánem. Můžete také vytvářet nové proměnné.

Máte na výběr; pevně zakódujte dva procesy nebo vytvořte kanál. První volba může vést k úniku dat a vytvářet nekonzistence v průběhu času. Lepší možností je použít potrubí.

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

Potrubí provede dvě operace, než naplní logistický klasifikátor:

  1. Standardizujte proměnnou: „StandardScaler()“
  2. Převeďte kategorické funkce: OneHotEncoder(sparse=False)

Tyto dva kroky můžete provést pomocí make_column_transformer. Tato funkce není v aktuální verzi scikit-learn (0.19) dostupná. V aktuální verzi není možné provádět kodér štítků a jeden hot kodér v potrubí. To je jeden z důvodů, proč jsme se rozhodli použít vývojářskou verzi.

make_column_transformer se snadno používá. Musíte definovat, které sloupce použít transformaci a jakou transformaci provozovat. Chcete-li například standardizovat spojitou funkci, můžete:

  • conti_features, StandardScaler() uvnitř make_column_transformer.
    • conti_features: seznam se spojitou proměnnou
    • StandardScaler: standardizace proměnné

Objekt OneHotEncoder uvnitř make_column_transformer automaticky zakóduje štítek.

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

Můžete otestovat, zda potrubí funguje pomocí fit_transform. Soubor dat by měl mít následující tvar: 26048, 107

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

Datový transformátor je připraven k použití. Potrubí můžete vytvořit pomocí make_pipeline. Jakmile jsou data transformována, můžete napájet logistickou regresi.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Trénink modelu pomocí scikit-learn je triviální. Musíte použít přizpůsobení objektu, kterému předchází potrubí, tj. model. Přesnost můžete vytisknout pomocí objektu skóre z knihovny scikit-learn

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

Nakonec můžete předpovídat třídy pomocí forecast_proba. Vrací pravděpodobnost pro každou třídu. Všimněte si, že se to rovná jedné.

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) Pomocí našeho potrubí při vyhledávání v mřížce

Ladění hyperparametru (proměnné, které určují strukturu sítě jako skryté jednotky) může být zdlouhavé a vyčerpávající.

Jedním ze způsobů hodnocení modelu by mohla být změna velikosti tréninkové sady a hodnocení výkonů.

Tuto metodu můžete desetkrát zopakovat, abyste viděli metriky skóre. Je to však příliš mnoho práce.

Místo toho scikit-learn poskytuje funkci pro ladění parametrů a křížovou validaci.

Křížová validace

Cross-Validation znamená, že během trénování se trénovací množina sklouzává nkrát v záhybech a poté model nkrát vyhodnocuje. Pokud je například cv nastaveno na 10, trénovací sada se natrénuje a vyhodnotí desetkrát. V každém kole si klasifikátor náhodně vybere devět záhybů pro trénování modelu a 10. záhyb je určen k vyhodnocení.

Vyhledávání v mřížce

Každý klasifikátor má hyperparametry k vyladění. Můžete vyzkoušet různé hodnoty nebo můžete nastavit mřížku parametrů. Pokud přejdete na oficiální web scikit-learn, můžete vidět, že logistický klasifikátor má různé parametry k vyladění. Pro urychlení tréninku zvolíte vyladění parametru C. Ovládá parametr regularizace. Mělo by to být pozitivní. Malá hodnota dává větší váhu regularizátoru.

Můžete použít objekt GridSearchCV. Musíte vytvořit slovník obsahující hyperparametry k ladění.

Vypíšete hyperparametry následované hodnotami, které chcete vyzkoušet. Chcete-li například vyladit parametr C, použijte:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: Parametru předchází název klasifikátoru v malých písmenech a dvě podtržítka.

Model vyzkouší čtyři různé hodnoty: 0.001, 0.01, 0.1 a 1.

Model trénujete pomocí 10 záhybů: 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 můžete trénovat pomocí GridSearchCV s parametrem gri a cv.

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

VÝSTUP

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)

Pro přístup k nejlepším parametrům použijte best_params_

grid_clf.best_params_

VÝSTUP

{'logisticregression__C': 1.0}

Po natrénování modelu se čtyřmi různými hodnotami regularizace je optimální parametr

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

nejlepší logistická regrese z vyhledávání v mřížce: 0.850891

Chcete-li získat přístup k předpokládaným pravděpodobnostem:

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 se scikit-learn

Zkusme příklady Scikit-learn, abychom vytrénovali jeden z nejlepších klasifikátorů na trhu. XGBoost je vylepšení oproti náhodnému lese. Teoretické pozadí klasifikátoru mimo rámec tohoto Python Scikit tutoriál. Mějte na paměti, že XGBoost vyhrál spoustu kaggle soutěží. S průměrnou velikostí datové sady může fungovat stejně dobře jako algoritmus hlubokého učení nebo dokonce lépe.

Klasifikátor je náročný na trénování, protože má vysoký počet parametrů k vyladění. Pro výběr parametru můžete samozřejmě použít GridSearchCV.

Místo toho se podívejme, jak využít lepší způsob, jak najít optimální parametry. GridSearchCV může být zdlouhavé a velmi zdlouhavé na trénování, pokud překonáte mnoho hodnot. Vyhledávací prostor roste spolu s počtem parametrů. Vhodnějším řešením je použití RandomizedSearchCV. Tato metoda spočívá v náhodném výběru hodnot každého hyperparametru po každé iteraci. Pokud je například klasifikátor trénován více než 1000 iterací, vyhodnotí se 1000 kombinací. Funguje to víceméně jako. GridSearchCV

Musíte importovat xgboost. Pokud knihovna není nainstalována, použijte prosím pip3 install xgboost nebo

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

In Jupyter životní prostředí

Dále

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

Další krok v tomto Scikitu Python výukový program obsahuje specifikaci parametrů k ladění. Všechny parametry k vyladění naleznete v oficiální dokumentaci. V zájmu Python Sklearn tutoriál, vyberete pouze dva hyperparametry se dvěma hodnotami každý. Trénink XGBoost zabere spoustu času, čím více hyperparametrů v mřížce, tím delší dobu musíte čekat.

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

Vytvoříte nový kanál s klasifikátorem XGBoost. Můžete definovat 600 odhadů. Všimněte si, že n_estimators jsou parametry, které můžete vyladit. Vysoká hodnota může vést k nadměrnému vybavení. Můžete sami vyzkoušet různé hodnoty, ale uvědomte si, že to může trvat hodiny. Pro ostatní parametry použijete výchozí hodnotu

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

Křížovou validaci můžete zlepšit pomocí křížového validátoru Stratified K-Folds. Zde vytvoříte pouze tři záhyby, abyste urychlili výpočet, ale snížili kvalitu. Zvyšte tuto hodnotu na 5 nebo 10 doma, abyste zlepšili výsledky.

Můžete si vybrat trénování modelu ve čtyřech iteracích.

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)

Náhodné vyhledávání je připraveno k použití, můžete model trénovat

#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 můžete vidět, XGBoost má lepší skóre než předchozí logisitc regrese.

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)

Vytvořte DNN pomocí MLPClassifier ve scikit-learn

Konečně můžete trénovat algoritmus hlubokého učení pomocí scikit-learn. Metoda je stejná jako u druhého klasifikátoru. Klasifikátor je k dispozici na MLPClassifier.

from sklearn.neural_network import MLPClassifier

Definujete následující algoritmus hlubokého učení:

  • Adam řešitel
  • Funkce aktivace Relu
  • Alfa = 0.0001
  • velikost dávky 150
  • Dvě skryté vrstvy se 100 a 50 neurony
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Pro vylepšení modelu můžete změnit počet vrstev

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

DNN regresní skóre: 0.821253

LIME: Důvěřujte svému modelu

Nyní, když máte dobrý model, potřebujete nástroj, abyste mu důvěřovali. Strojové učení Algoritmus, zejména náhodný les a neuronová síť, jsou známy jako algoritmus černé skříňky. Řekni to jinak, funguje to, ale nikdo neví proč.

Tři výzkumníci přišli se skvělým nástrojem, jak zjistit, jak počítač předpovídá. List se jmenuje Proč bych ti měl věřit?

Vyvinuli algoritmus s názvem Local Interpretable Model-Agnostic Explanations (LIME).

Vezměte si příklad:

někdy nevíte, jestli můžete věřit predikci strojového učení:

Lékař například nemůže věřit diagnóze jen proto, že to řekl počítač. Před uvedením do výroby musíte také vědět, zda modelu můžete důvěřovat.

Představte si, že dokážeme pochopit, proč jakýkoli klasifikátor předpovídá i neuvěřitelně komplikované modely, jako jsou neuronové sítě, náhodné lesy nebo svms s jakýmkoli jádrem

bude přístupnější důvěřovat předpovědi, pokud pochopíme její důvody. Z příkladu s lékařem, pokud mu model řekl, které příznaky jsou zásadní, důvěřovali byste mu, je také snazší zjistit, zda byste modelu neměli věřit.

Lime vám může říct, jaké vlastnosti ovlivňují rozhodnutí klasifikátoru

Příprava dat

Je to několik věcí, které musíte změnit, abyste mohli provozovat LIME krajta. Nejprve musíte do terminálu nainstalovat vápno. Můžete použít pip install vápno

Lime využívá objekt LimeTabularExplainer k místní aproximaci modelu. Tento objekt vyžaduje:

  • datovou sadu ve formátu numpy
  • Název funkcí: feature_names
  • Název tříd: class_names
  • Index sloupce kategorických prvků: categorical_features
  • Název skupiny pro každý kategorický prvek: categorical_names

Vytvořte nudnou vlakovou soupravu

Můžete zkopírovat a převést df_train z pand do otupělý velmi lehce

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

Získejte název třídy Štítek je přístupný pomocí objektu unique(). Měl bys vidět:

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

index sloupce kategoriálních znaků

K získání názvu skupiny můžete použít metodu, kterou jste před tím naklonili. Štítek zakódujete pomocí LabelEncoder. Opakujete operaci se všemi kategorickými prvky.

## 
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

Nyní, když je datová sada připravena, můžete sestavit jinou datovou sadu, jak je uvedeno níže v příkladech učení Scikit. Ve skutečnosti transformujete data mimo potrubí, abyste se vyhnuli chybám s LIME. Tréninková sada v LimeTabularExplainer by měla být numpy pole bez řetězce. Pomocí výše uvedené metody máte již trénovací datovou sadu převedenou.

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)

Z XGBoost můžete udělat potrubí s optimálními parametry

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))])

Dostanete varování. Varování vysvětluje, že není nutné vytvářet kodér štítků před kanálem. Pokud nechcete používat LIME, můžete použít metodu z první části výukového programu Machine Learning with Scikit-learn. V opačném případě můžete zůstat u této metody, nejprve vytvořte kódovanou datovou sadu, nastavte kodér get hot one v rámci kanálu.

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)

Než použijeme LIME v akci, vytvořte numpy pole s vlastnostmi nesprávné klasifikace. Tento seznam můžete použít později, abyste získali představu o tom, co klasifikátor klame.

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)

Vytvoříte funkci lambda pro načtení predikce z modelu s novými daty. Brzy to budete potřebovat.

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]])

Převedete datový rámec pandy na numpy pole

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)

Vyberme si náhodnou domácnost z testovací sady a podívejme se na předpověď modelu a na to, jak si počítač vybral.

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])

Ke kontrole vysvětlení za modelem můžete použít vysvětlující modul s vysvětlením_instance

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

Příprava dat

Vidíme, že klasifikátor předpověděl domácnost správně. Příjem je skutečně přes 50 tis.

První věc, kterou můžeme říci, je, že klasifikátor si není tak jistý předpovídanými pravděpodobnostmi. Automat předpovídá, že domácnost má příjem nad 50 tisíc s pravděpodobností 64 %. Těchto 64 % tvoří kapitálový zisk a manželství. Modrá barva přispívá negativně k pozitivní třídě a oranžová linie pozitivně.

Klasifikátor je zmatený, protože kapitálový zisk této domácnosti je nulový, zatímco kapitálový zisk je obvykle dobrým prediktorem bohatství. Kromě toho domácnost pracuje méně než 40 hodin týdně. Věk, povolání a pohlaví přispívají ke klasifikátoru pozitivně.

Pokud by byl rodinný stav svobodný, klasifikátor by předpověděl příjem pod 50 0.64 (0.18-0.46 = XNUMX)

Můžeme to zkusit s jinou domácností, která byla špatně zařazena

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)

Příprava dat

Klasifikátor předpověděl příjem pod 50 60, ačkoli to není pravda. Tahle domácnost vypadá divně. Nemá kapitálový zisk, ani kapitálovou ztrátu. Je rozvedený, je mu 12 let a je to vzdělaný člověk, tj. vzdělání_číslo > 50. Podle celkového vzorce by tato domácnost měla, jak vysvětluje klasifikátor, dostávat příjem pod XNUMX tisíc.

Zkuste si pohrát s LIME. U klasifikátoru si všimnete hrubých chyb.

Můžete zkontrolovat GitHub vlastníka knihovny. Poskytují další dokumentaci pro klasifikaci obrázků a textu.

Shrnutí

Níže je uveden seznam některých užitečných příkazů ve verzi scikit learn >=0.20

vytvořit datovou sadu vlaku/testu stážisté se rozdělí
Vybudujte potrubí
vyberte sloupec a použijte transformaci makecolumntransformer
typ transformace
standardizovat StandardScaler
min. max MinMaxScaler
Normalizovat Normalizátor
Imputujte chybějící hodnotu přičítat
Převést kategorické OneHotEncoder
Přizpůsobte a transformujte data fit_transform
Vytvořte potrubí make_pipeline
Základní model
logistické regrese Logistická regrese
XGBoost XGBClassifier
Neuronová síť Klasifikátor MLPC
Vyhledávání v mřížce GridSearchCV
Randomizované vyhledávání RandomizedSearchCV