Scikit-Learn Tutorial: Sådan installeres & Scikit-Learn eksempler

Hvad er Scikit-learn?

Scikit-lære er en open source Python bibliotek til maskinlæring. Det understøtter state-of-the-art algoritmer såsom KNN, XGBoost, random forest og SVM. Den er bygget oven på NumPy. Scikit-learn er meget udbredt i Kaggle-konkurrencen såvel som fremtrædende teknologivirksomheder. Det hjælper med forbehandling, dimensionalitetsreduktion (parametervalg), klassificering, regression, klyngedannelse og modelvalg.

Scikit-learn har den bedste dokumentation af alle open source-biblioteker. Det giver dig et interaktivt diagram på https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Sådan fungerer Scikit Learn
Sådan fungerer Scikit Learn

Scikit-learn er ikke særlig svært at bruge og giver fremragende resultater. Scikit learning understøtter dog ikke parallelle beregninger. Det er muligt at køre en deep learning-algoritme med det, men det er ikke en optimal løsning, især hvis du ved, hvordan du bruger TensorFlow.

Sådan downloades og installeres Scikit-learn

Nu i dette Python Scikit-learn tutorial, vi lærer, hvordan du downloader og installerer Scikit-learn:

Mulighed 1: AWS

scikit-learn kan bruges over AWS. Vær venlig henvise Docker-billedet, der har scikit-learn forudinstalleret.

For at bruge udviklerversion skal du bruge kommandoen i Jupyter

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

Mulighed 2: Mac eller Windows ved hjælp af Anaconda

For at lære om Anaconda installation se https://www.guru99.com/download-install-tensorflow.html

For nylig har udviklerne af scikit udgivet en udviklingsversion, der tackler almindelige problemer, som den nuværende version står over for. Vi fandt det mere bekvemt at bruge udviklerversionen i stedet for den nuværende version.

Sådan installeres scikit-learn med Conda Environment

Hvis du installerede scikit-learn med conda-miljøet, skal du følge trinnet for at opdatere til version 0.20

Trin 1) Aktiver tensorflow-miljø

source activate hello-tf

Trin 2) Fjern scikit lean ved hjælp af conda-kommandoen

conda remove scikit-learn

Trin 3) Installer udviklerversion.
Installer scikit learn udviklerversion sammen med nødvendige biblioteker.

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

BEMÆRK VENLIGST: Windows brugeren skal installere Microsoft Visuel C++ 14. Du kan få det fra link.

Scikit-Learn Eksempel med Machine Learning

Denne Scikit-tutorial er opdelt i to dele:

  1. Maskinlæring med scikit-learn
  2. Sådan stoler du på din model med LIME

Den første del beskriver, hvordan man bygger en pipeline, opretter en model og tuner hyperparametrene, mens den anden del giver state-of-the-art med hensyn til modelvalg.

Trin 1) Importer dataene

I løbet af denne Scikit-læringsvejledning vil du bruge voksendatasættet.

For en baggrund i dette datasæt henvises til Hvis du er interesseret i at vide mere om den beskrivende statistik, skal du bruge værktøjerne Dive og Overview.

Der henvises denne tutorial lær mere om dyk og overblik

Du importerer datasættet med Pandas. Bemærk, at du skal konvertere typen af ​​de kontinuerlige variable i float-format.

Dette datasæt indeholder otte kategoriske variable:

De kategoriske variabler er opført i CATE_FEATURES

  • arbejdsklasse
  • uddannelse
  • ægteskabelig
  • besættelse
  • forhold
  • løb
  • køn
  • oprindelses land

desuden seks kontinuerte variable:

De kontinuerte variable er opført i CONTI_FEATURES

  • alder
  • fnlwgt
  • uddannelsesnummer
  • kapitalgevinst
  • kapitaltab
  • timer_uge

Bemærk, at vi udfylder listen i hånden, så du har en bedre ide om, hvilke kolonner vi bruger. En hurtigere måde at konstruere en liste over kategoriske eller kontinuerlige er at bruge:

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

Her er koden til at importere dataene:

# 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()
alder fnlwgt uddannelsesnummer kapitalgevinst kapitaltab timer_uge
tælle 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
betyde 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
minut 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

Du kan kontrollere antallet af unikke værdier for native_country-funktionerne. Man kan se, at kun én husstand kommer fra Holand-Holland. Denne husstand vil ikke give os nogen information, men vil gennem en fejl under træningen.

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

Du kan ekskludere denne uinformative række fra datasættet

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

Dernæst gemmer du placeringen af ​​de kontinuerlige funktioner i en liste. Du skal bruge det i næste trin for at bygge rørledningen.

Koden nedenfor vil gå over alle kolonnenavne i CONTI_FEATURES og få dens placering (dvs. dens nummer) og derefter tilføje den til en liste kaldet 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]

Koden nedenfor udfører det samme job som ovenfor, men for den kategoriske variabel. Koden nedenfor gentager, hvad du har gjort tidligere, undtagen med de kategoriske funktioner.

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

Du kan se på datasættet. Bemærk, at hver kategorisk funktion er en streng. Du kan ikke fodre en model med en strengværdi. Du skal transformere datasættet ved hjælp af en dummy-variabel.

df_train.head(5)

Faktisk skal du oprette en kolonne for hver gruppe i funktionen. Først kan du køre koden nedenfor for at beregne det samlede antal kolonner, der er nødvendige.

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

Hele datasættet indeholder 101 grupper som vist ovenfor. For eksempel har arbejdsklassens funktioner ni grupper. Du kan visualisere navnet på grupperne med følgende koder

unique() returnerer de unikke værdier af de kategoriske funktioner.

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

Derfor vil træningsdatasættet indeholde 101 + 7 kolonner. De sidste syv kolonner er de kontinuerlige træk.

Scikit-learn kan tage sig af konverteringen. Det gøres i to trin:

  • Først skal du konvertere strengen til ID. For eksempel vil State-gov have ID 1, Self-emp-not-inc ID 2 og så videre. Funktionen LabelEncoder gør dette for dig
  • Transponer hvert ID til en ny kolonne. Som nævnt før har datasættet 101-gruppens ID. Derfor vil der være 101 kolonner, der fanger alle kategoriske funktioners grupper. Scikit-learn har en funktion kaldet OneHotEncoder, der udfører denne operation

Trin 2) Opret tog-/testsættet

Nu hvor datasættet er klar, kan vi dele det 80/20.

80 procent for træningssættet og 20 procent for testsættet.

Du kan bruge train_test_split. Det første argument er datarammen er funktionerne og det andet argument er labeldatarammen. Du kan angive størrelsen på testsættet med 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)

Trin 3) Byg rørledningen

Pipelinen gør det nemmere at fodre modellen med konsistente data.

Tanken bag er at lægge rådataene ind i en 'pipeline' for at udføre operationer.

For eksempel skal du med det aktuelle datasæt standardisere de kontinuerlige variable og konvertere de kategoriske data. Bemærk, at du kan udføre enhver operation inde i rørledningen. For eksempel, hvis du har 'NA'er' i datasættet, kan du erstatte dem med middelværdien eller medianen. Du kan også oprette nye variabler.

Du har valget; hårdkode de to processer eller opret en pipeline. Det første valg kan føre til datalækage og skabe uoverensstemmelser over tid. En bedre mulighed er at bruge rørledningen.

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

Rørledningen vil udføre to operationer, før den logistiske klassifikator fødes:

  1. Standardiser variablen: `StandardScaler()“
  2. Konverter de kategoriske funktioner: OneHotEncoder(sparse=False)

Du kan udføre de to trin ved hjælp af make_column_transformer. Denne funktion er ikke tilgængelig i den aktuelle version af scikit-learn (0.19). Det er ikke muligt med den aktuelle version at udføre labelencoderen og en hot encoder i pipeline. Det er en af ​​grundene til, at vi besluttede at bruge udviklerversionen.

make_column_transformer er nem at bruge. Du skal definere, hvilke kolonner der skal anvendes transformationen, og hvilken transformation der skal udføres. For at standardisere den kontinuerlige funktion kan du for eksempel gøre:

  • conti_features, StandardScaler() inde i make_column_transformer.
    • conti_features: liste med den kontinuerlige variabel
    • StandardScaler: standardiser variablen

Objektet OneHotEncoder inde i make_column_transformer koder automatisk etiketten.

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

Du kan teste om pipelinen fungerer med fit_transform. Datasættet skal have følgende form: 26048, 107

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

Datatransformatoren er klar til brug. Du kan oprette pipelinen med make_pipeline. Når dataene er transformeret, kan du fodre den logistiske regression.

model = make_pipeline(
    preprocess,
    LogisticRegression())

At træne en model med scikit-learn er trivielt. Du skal bruge den objekttilpasning, der er forudgået af pipeline, dvs. modellen. Du kan udskrive nøjagtigheden med partiturobjektet fra scikit-learn-biblioteket

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

Endelig kan du forudsige klasserne med predict_proba. Det returnerer sandsynligheden for hver klasse. Bemærk, at det summer til én.

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

Trin 4) Brug af vores pipeline i en gittersøgning

Justering af hyperparameteren (variabler, der bestemmer netværksstruktur som skjulte enheder) kan være trættende og udmattende.

En måde at evaluere modellen på kunne være at ændre størrelsen på træningssættet og evaluere præstationerne.

Du kan gentage denne metode ti gange for at se score-metrics. Det er dog for meget arbejde.

I stedet giver scikit-learn en funktion til at udføre parameterjustering og krydsvalidering.

Krydsvalidering

Krydsvalidering betyder under træningen, at træningssættet glider n antal gange i folder og evaluerer derefter modellen n gang. For eksempel, hvis cv er sat til 10, trænes træningssættet og evalueres ti gange. Ved hver runde vælger klassificereren tilfældigt ni fold for at træne modellen, og den 10. fold er beregnet til evaluering.

Netsøgning

Hver klassifikator har hyperparametre til at indstille. Du kan prøve forskellige værdier, eller du kan indstille et parametergitter. Hvis du går til den officielle scikit-learn hjemmeside, kan du se, at den logistiske klassificering har forskellige parametre at indstille. For at gøre træningen hurtigere vælger du at tune C-parameteren. Den kontrollerer for regulariseringsparameteren. Det skal være positivt. En lille værdi giver mere vægt til regularizeren.

Du kan bruge objektet GridSearchCV. Du skal oprette en ordbog, der indeholder hyperparametrene for at indstille.

Du angiver hyperparametrene efterfulgt af de værdier, du vil prøve. For eksempel, for at indstille C-parameteren, bruger du:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: Parameteren indledes med navnet på klassifikatoren med små bogstaver og to understregninger.

Modellen vil prøve fire forskellige værdier: 0.001, 0.01, 0.1 og 1.

Du træner modellen ved hjælp af 10 fold: cv=10

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

Du kan træne modellen ved hjælp af GridSearchCV med parameteren gri og cv.

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

PRODUKTION

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)

For at få adgang til de bedste parametre, bruger du best_params_

grid_clf.best_params_

PRODUKTION

{'logisticregression__C': 1.0}

Efter at have trænet modellen med fire forskellige regulariseringsværdier er den optimale parameter

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

bedste logistiske regression fra gittersøgning: 0.850891

Sådan får du adgang til de forudsagte sandsynligheder:

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

XGBoost-model med scikit-learn

Lad os prøve Scikit-learn-eksempler for at træne en af ​​de bedste klassifikatorer på markedet. XGBoost er en forbedring i forhold til den tilfældige skov. Klassifikatorens teoretiske baggrund uden for rammerne af dette Python Scikit tutorial. Husk på, at XGBoost har vundet masser af kaggle-konkurrencer. Med en gennemsnitlig datasætstørrelse kan den fungere lige så godt som en dyb læringsalgoritme eller endnu bedre.

Klassificeringen er udfordrende at træne, fordi den har et stort antal parametre, der skal indstilles. Du kan selvfølgelig bruge GridSearchCV til at vælge parameteren for dig.

Lad os i stedet se, hvordan man bruger en bedre måde at finde de optimale parametre på. GridSearchCV kan være trættende og meget lang tid at træne, hvis du består mange værdier. Søgerummet vokser sammen med antallet af parametre. En foretrukken løsning er at bruge RandomizedSearchCV. Denne metode består i at vælge værdierne for hver hyperparameter efter hver iteration tilfældigt. For eksempel, hvis klassificereren trænes over 1000 iterationer, evalueres 1000 kombinationer. Det fungerer mere eller mindre som. GridSearchCV

Du skal importere xgboost. Hvis biblioteket ikke er installeret, skal du bruge pip3 install xgboost eller

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

In Jupyter miljø

Dernæst

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

Det næste trin i denne Scikit Python tutorial inkluderer specificering af de parametre, der skal indstilles. Du kan henvise til den officielle dokumentation for at se alle de parametre, der skal indstilles. Af hensyn til Python Sklearn tutorial, du vælger kun to hyperparametre med to værdier hver. XGBoost tager meget tid at træne, jo flere hyperparametre i gitteret, jo længere tid skal du vente.

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

Du konstruerer en ny pipeline med XGBoost-klassifikator. Du vælger at definere 600 estimatorer. Bemærk, at n_estimators er en parameter, som du kan justere. En høj værdi kan føre til overfitting. Du kan selv prøve forskellige værdier, men vær opmærksom på, at det kan tage timer. Du bruger standardværdien for de andre parametre

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

Du kan forbedre krydsvalideringen med den Stratified K-Folds krydsvalidator. Du konstruerer kun tre fold her for at gøre beregningen hurtigere, men for at sænke kvaliteten. Forøg denne værdi til 5 eller 10 derhjemme for at forbedre resultaterne.

Du vælger at træne modellen over fire iterationer.

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)

Den randomiserede søgning er klar til brug, du kan træne modellen

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

Som du kan se, har XGBoost en bedre score end den tidligere logistiske regression.

print("Bedste parameter", random_search.best_params_)
print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
Bedste 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)

Opret DNN med MLPClassifier i scikit-learn

Endelig kan du træne en dyb læringsalgoritme med scikit-learn. Metoden er den samme som den anden klassifikator. Klassificeringen er tilgængelig på MLPClassifier.

from sklearn.neural_network import MLPClassifier

Du definerer følgende deep learning-algoritme:

  • Adam løser
  • Relu aktiveringsfunktion
  • Alfa = 0.0001
  • batchstørrelse på 150
  • To skjulte lag med henholdsvis 100 og 50 neuroner
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Du kan ændre antallet af lag for at forbedre modellen

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

DNN-regressionsscore: 0.821253

LIME: Stol på din model

Nu hvor du har en god model, har du brug for et værktøj til at stole på den. Maskinelæring algoritmer, især tilfældige skov og neurale netværk, er kendt for at være black-box algoritme. Sig anderledes, det virker, men ingen ved hvorfor.

Tre forskere har fundet frem til et fantastisk værktøj til at se, hvordan computeren laver en forudsigelse. Avisen hedder Why Should I Trust You?

De udviklede en algoritme ved navn Lokale fortolkbare model-agnostiske forklaringer (LIME).

Tag et eksempel:

nogle gange ved du ikke, om du kan stole på en maskinlæringsforudsigelse:

En læge kan for eksempel ikke stole på en diagnose, bare fordi en computer sagde det. Du skal også vide, om du kan stole på modellen, før du sætter den i produktion.

Forestil dig, at vi kan forstå, hvorfor enhver klassifikator laver en forudsigelse, selv utroligt komplicerede modeller såsom neurale netværk, tilfældige skove eller svms med enhver kerne

vil blive mere tilgængelig for at stole på en forudsigelse, hvis vi kan forstå årsagerne bag den. Fra eksemplet med lægen, hvis modellen fortalte ham, hvilke symptomer der er essentielle, du ville stole på den, er det også lettere at finde ud af, om du ikke skal stole på modellen.

Lime kan fortælle dig, hvilke funktioner der påvirker klassifikatorens beslutninger

Dataforberedelse

Det er et par ting, du skal ændre for at køre LIME med python. Først og fremmest skal du installere kalk i terminalen. Du kan bruge pip install kalk

Lime gør brug af LimeTabularExplainer-objektet til at tilnærme modellen lokalt. Dette objekt kræver:

  • et datasæt i numpy-format
  • Navnet på funktionerne: feature_names
  • Navnet på klasserne: klassenavne
  • Indekset for kolonnen af ​​kategoriske funktioner: categorical_features
  • Navnet på gruppen for hvert kategoriske træk: kategoriske_navne

Opret numpy togsæt

Du kan kopiere og konvertere df_train fra pandaer til bedøvet meget let

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

Få klassens navn Etiketten er tilgængelig med objektet unique(). Du bør se:

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

indeks over kolonnen af ​​de kategoriske træk

Du kan bruge den metode, du læner dig før, for at få navnet på gruppen. Du koder etiketten med LabelEncoder. Du gentager operationen på alle de kategoriske træk.

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

Nu hvor datasættet er klar, kan du konstruere det forskellige datasæt som vist i nedenstående Scikit learning-eksempler. Du transformerer faktisk dataene uden for pipelinen for at undgå fejl med LIME. Træningssættet i LimeTabularExplainer skal være et numpy array uden streng. Med metoden ovenfor har du allerede konverteret et træningsdatasæt.

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)

Du kan lave pipelinen med de optimale parametre fra 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))])

Du får en advarsel. Advarslen forklarer, at du ikke behøver at oprette en etiketkoder før pipelinen. Hvis du ikke vil bruge LIME, kan du fint bruge metoden fra første del af Machine Learning with Scikit-learn tutorial. Ellers kan du fortsætte med denne metode, først oprette et kodet datasæt, sæt få den varme enkoder i pipelinen.

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)

Før vi bruger LIME i aktion, lad os skabe et numpy array med funktionerne i den forkerte klassifikation. Du kan bruge denne liste senere til at få en idé om, hvad der vildleder klassificereren.

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)

Du opretter en lambda-funktion til at hente forudsigelsen fra modellen med de nye data. Du får brug for det snart.

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

Du konverterer pandas-datarammen til numpy-array

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)

Lad os vælge en tilfældig husstand fra testsættet og se modelforudsigelsen og hvordan computeren foretog sit valg.

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

Du kan bruge forklaringen med explain_instance til at tjekke forklaringen bag modellen

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

Dataforberedelse

Vi kan se, at klassificereren forudsagde husstanden korrekt. Indkomsten er faktisk over 50k.

Det første, vi kan sige, er, at klassifikatoren ikke er så sikker på de forudsagte sandsynligheder. Maskinen forudsiger, at husstanden har en indkomst på over 50k med en sandsynlighed på 64%. Disse 64% består af kapitalgevinst og ægteskab. Den blå farve bidrager negativt til den positive klasse og den orange streg positivt.

Klassifikatoren er forvirret, fordi kapitalgevinsten i denne husstand er nul, mens kapitalgevinsten normalt er en god forudsigelse for velstand. Desuden arbejder husstanden mindre end 40 timer om ugen. Alder, erhverv og køn bidrager positivt til klassificeringen.

Hvis den ægteskabelige status var single, ville klassificereren have forudsagt en indkomst under 50k (0.64-0.18 = 0.46)

Vi kan prøve med en anden husstand, som er blevet forkert klassificeret

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)

Dataforberedelse

Klassifikatoren forudsagde en indkomst under 50k, mens det er usandt. Denne husstand virker underlig. Det har ikke en kursgevinst eller kurstab. Han er skilt og er 60 år gammel, og det er et uddannet folk, dvs. uddannelse_num > 12. Ifølge det overordnede mønster skulle denne husstand, som klassificereren forklarer, få en indkomst under 50k.

Du prøver at lege med LIME. Du vil bemærke grove fejl fra klassificereren.

Du kan tjekke GitHub for ejeren af ​​biblioteket. De giver ekstra dokumentation for billed- og tekstklassificering.

Resumé

Nedenfor er en liste over nogle nyttige kommandoer med scikit learning version >=0.20

oprette tog-/testdatasæt praktikanter splittes
Byg en pipeline
vælg kolonnen og anvend transformationen lav kolonnetransformer
form for transformation
standardisere StandardScaler
min max MinMaxScaler
Normalisér Normalisator
Angiv manglende værdi tilregne
Konverter kategorisk OneHotEncoder
Tilpas og transformer dataene fit_transform
Lav rørledningen make_pipeline
Grundlæggende model
Logistisk regression Logistisk regression
XGBoost XGBClassifier
Neuralt net MLPClassifier
Netsøgning GridSearchCV
Randomiseret søgning RandomizedSearchCV