Scikit-Learn Tutorial: Hvordan installere og Scikit-Learn eksempler

Hva er Scikit-learn?

Scikit lære er en åpen kildekode Python bibliotek for maskinlæring. Den støtter state-of-the-art algoritmer som KNN, XGBoost, random forest og SVM. Den er bygget på toppen av NumPy. Scikit-learn er mye brukt i Kaggle-konkurranse så vel som fremtredende teknologiselskaper. Det hjelper med forbehandling, dimensjonalitetsreduksjon (parametervalg), klassifisering, regresjon, gruppering og modellvalg.

Scikit-learn har den beste dokumentasjonen av alle åpen kildekode-biblioteker. Det gir deg et interaktivt diagram på https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Hvordan Scikit Learn fungerer
Hvordan Scikit Learn fungerer

Scikit-learn er ikke veldig vanskelig å bruke og gir utmerkede resultater. Scikit learning støtter imidlertid ikke parallelle beregninger. Det er mulig å kjøre en dyp læringsalgoritme med det, men det er ikke en optimal løsning, spesielt hvis du vet hvordan du bruker TensorFlow.

Hvordan laste ned og installere Scikit-learn

Nå i dette Python Scikit-learn tutorial, vi vil lære hvordan du laster ned og installerer Scikit-learn:

Alternativ 1: AWS

scikit-learn kan brukes over AWS. Vennligst referere Docker-bildet som har scikit-learn forhåndsinstallert.

For å bruke utviklerversjonen, bruk kommandoen i Jupyter

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

Alternativ 2: Mac eller Windows bruker Anaconda

For å lære om Anaconda-installasjon, se https://www.guru99.com/download-install-tensorflow.html

Nylig har utviklerne av scikit gitt ut en utviklingsversjon som takler vanlige problemer med den nåværende versjonen. Vi fant det mer praktisk å bruke utviklerversjonen i stedet for den nåværende versjonen.

Hvordan installere scikit-learn med Conda Environment

Hvis du installerte scikit-learn med conda-miljøet, følg trinnet for å oppdatere til versjon 0.20

Trinn 1) Aktiver tensorflow-miljøet

source activate hello-tf

Trinn 2) Fjern scikit lean ved å bruke conda-kommandoen

conda remove scikit-learn

Trinn 3) Installer utviklerversjon.
Installer scikit learn utviklerversjon 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

NOTAT: Windows brukeren må installere Microsoft Visual C++ 14. Du kan få det fra her.

Scikit-Learn-eksempel med maskinlæring

Denne Scikit-opplæringen er delt inn i to deler:

  1. Maskinlæring med scikit-learn
  2. Hvordan stole på modellen din med LIME

Den første delen beskriver hvordan du bygger en rørledning, lager en modell og justerer hyperparametrene, mens den andre delen gir toppmoderne når det gjelder modellvalg.

Trinn 1) Importer dataene

I løpet av denne Scikit-læringsopplæringen vil du bruke voksendatasettet.

For en bakgrunn i dette datasettet, se Hvis du er interessert i å vite mer om den beskrivende statistikken, vennligst bruk Dive og Overview-verktøy.

Henvis denne opplæringen lær mer om dykk og oversikt

Du importerer datasettet med Pandas. Merk at du må konvertere typen av de kontinuerlige variablene i flyteformat.

Dette datasettet inkluderer åtte kategoriske variabler:

De kategoriske variablene er oppført i CATE_FEATURES

  • arbeidsklasse
  • utdanning
  • ekteskapelig
  • okkupasjon
  • forholdet
  • rase
  • kjønn
  • native_country

dessuten seks kontinuerlige variabler:

De kontinuerlige variablene er oppført i CONTI_FEATURES

  • alder
  • fnlwgt
  • utdanning_nummer
  • kapitalgevinst
  • kapitaltap
  • timer_uke

Merk at vi fyller listen for hånd slik at du har en bedre oversikt over hvilke kolonner vi bruker. En raskere måte å konstruere en liste over kategoriske eller kontinuerlige er å bruke:

## 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 for å 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 utdanning_nummer kapitalgevinst kapitaltap timer_uke
telle 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
bety 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
minutter 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 sjekke antallet unike verdier for native_country-funksjonene. Du kan se at kun én husstand kommer fra Holand-Nederland. Denne husstanden vil ikke gi oss noen informasjon, men vil gjennom en feil under treningen.

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 raden fra datasettet

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

Deretter lagrer du posisjonen til de kontinuerlige funksjonene i en liste. Du trenger det i neste trinn for å bygge rørledningen.

Koden nedenfor vil gå over alle kolonnenavnene i CONTI_FEATURES og hente plasseringen (dvs. nummeret) og deretter legge den til en liste kalt 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 gjør samme jobb som ovenfor, men for den kategoriske variabelen. Koden nedenfor gjentar det du har gjort tidligere, bortsett fra med de kategoriske funksjonene.

## 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 ta en titt på datasettet. Merk at hvert kategorisk trekk er en streng. Du kan ikke mate en modell med en strengverdi. Du må transformere datasettet ved å bruke en dummy-variabel.

df_train.head(5)

Faktisk må du opprette én kolonne for hver gruppe i funksjonen. Først kan du kjøre koden nedenfor for å beregne det totale antallet kolonner som trengs.

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 datasettet inneholder 101 grupper som vist ovenfor. For eksempel har arbeidsklassens funksjoner ni grupper. Du kan visualisere navnet på gruppene med følgende koder

unique() returnerer de unike verdiene til de kategoriske funksjonene.

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 opplæringsdatasettet inneholde 101 + 7 kolonner. De siste syv kolonnene er de kontinuerlige funksjonene.

Scikit-learn kan ta seg av konverteringen. Det gjøres i to trinn:

  • Først må du konvertere strengen til ID. For eksempel vil State-gov ha ID 1, Self-emp-not-inc ID 2 og så videre. Funksjonen LabelEncoder gjør dette for deg
  • Transponer hver ID til en ny kolonne. Som nevnt tidligere har datasettet 101-gruppens ID. Derfor vil det være 101 kolonner som fanger opp alle kategoriske funksjoners grupper. Scikit-learn har en funksjon kalt OneHotEncoder som utfører denne operasjonen

Trinn 2) Lag toget/testsettet

Nå som datasettet er klart, kan vi dele det 80/20.

80 prosent for treningssettet og 20 prosent for testsettet.

Du kan bruke train_test_split. Det første argumentet er datarammen er funksjonene og det andre argumentet er etiketten datarammen. Du kan spesifisere størrelsen på testsettet 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)

Trinn 3) Bygg rørledningen

Rørledningen gjør det enklere å mate modellen med konsistente data.

Tanken bak er å sette rådataene inn i en "pipeline" for å utføre operasjoner.

For eksempel, med det gjeldende datasettet, må du standardisere de kontinuerlige variablene og konvertere de kategoriske dataene. Merk at du kan utføre alle operasjoner inne i rørledningen. For eksempel, hvis du har 'NA'er' i datasettet, kan du erstatte dem med gjennomsnittet eller medianen. Du kan også opprette nye variabler.

Du har valget; hardkode de to prosessene eller lag en pipeline. Førstevalget kan føre til datalekkasje og skape inkonsekvenser over tid. Et bedre alternativ er å bruke 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 utføre to operasjoner før den mater den logistiske klassifisereren:

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

Du kan utføre de to trinnene ved å bruke make_column_transformer. Denne funksjonen er ikke tilgjengelig i gjeldende versjon av scikit-learn (0.19). Det er ikke mulig med gjeldende versjon å utføre etikettkoderen og én varmkoder i rørledningen. Det er en grunn til at vi bestemte oss for å bruke utviklerversjonen.

make_column_transformer er enkel å bruke. Du må definere hvilke kolonner som skal brukes transformasjonen og hvilken transformasjon som skal brukes. For å standardisere den kontinuerlige funksjonen kan du for eksempel gjøre:

  • conti_features, StandardScaler() inne i make_column_transformer.
    • conti_features: liste med den kontinuerlige variabelen
    • StandardScaler: standardiser variabelen

Objektet OneHotEncoder inne 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 rørledningen fungerer med fit_transform. Datasettet skal ha følgende form: 26048, 107

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

Datatransformatoren er klar til bruk. Du kan lage pipeline med make_pipeline. Når dataene er transformert, kan du mate den logistiske regresjonen.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Å trene en modell med scikit-learn er trivielt. Du må bruke objekttilpasningen innledet av rørledningen, dvs. modellen. Du kan skrive ut nøyaktigheten 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

Til slutt kan du forutsi klassene med predict_proba. Den returnerer sannsynligheten for hver klasse. Merk at det summerer 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]])

Trinn 4) Bruk av rørledningen vår i et rutenettsøk

Justering av hyperparameteren (variabler som bestemmer nettverksstruktur som skjulte enheter) kan være kjedelig og utmattende.

En måte å evaluere modellen på kan være å endre størrelsen på treningssettet og evaluere prestasjonene.

Du kan gjenta denne metoden ti ganger for å se poengsummene. Det er imidlertid for mye arbeid.

I stedet gir scikit-learn en funksjon for å utføre parameterinnstilling og kryssvalidering.

Kryssvalidering

Cross-Validation betyr under treningen, treningssettet er slip n antall ganger i folder og deretter evaluerer modellen n gang. For eksempel, hvis cv er satt til 10, trenes treningssettet og evalueres ti ganger. Ved hver runde velger klassifisereren tilfeldig ni fold for å trene modellen, og den 10. folden er ment for evaluering.

Rutenettsøk

Hver klassifikator har hyperparametre for å stille inn. Du kan prøve forskjellige verdier, eller du kan angi et parameterrutenett. Hvis du går til det offisielle nettstedet for scikit-learn, kan du se at den logistiske klassifikatoren har forskjellige parametere å justere. For å gjøre treningen raskere velger du å stille inn C-parameteren. Den kontrollerer for regulariseringsparameteren. Det skal være positivt. En liten verdi gir mer vekt til regularizeren.

Du kan bruke objektet GridSearchCV. Du må lage en ordbok som inneholder hyperparametrene for å stille inn.

Du lister opp hyperparametrene etterfulgt av verdiene du vil prøve. For å stille inn C-parameteren bruker du for eksempel:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: Parameteren innledes med navnet, med små bokstaver, på klassifikatoren og to understrekinger.

Modellen vil prøve fire forskjellige verdier: 0.001, 0.01, 0.1 og 1.

Du trener modellen ved å bruke 10 folder: 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 trene modellen ved å bruke GridSearchCV med parameterne gri og cv.

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

UTGANG

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 å få tilgang til de beste parameterne bruker du best_params_

grid_clf.best_params_

UTGANG

{'logisticregression__C': 1.0}

Etter å ha trent modellen med fire forskjellige regulariseringsverdier, er den optimale parameteren

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

beste logistiske regresjon fra rutenettsøk: 0.850891

For å få tilgang til de anslåtte sannsynlighetene:

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-modell med scikit-learn

La oss prøve Scikit-learn-eksempler for å trene en av de beste klassifisere på markedet. XGBoost er en forbedring i forhold til den tilfeldige skogen. Klassifisererens teoretiske bakgrunn utenfor rammen av dette Python Scikit opplæring. Husk at XGBoost har vunnet mange kaggle-konkurranser. Med en gjennomsnittlig datasettstørrelse kan den yte like bra som en dyplæringsalgoritme eller enda bedre.

Klassifisereren er utfordrende å trene fordi den har et stort antall parametere å stille inn. Du kan selvfølgelig bruke GridSearchCV til å velge parameteren for deg.

La oss i stedet se hvordan du bruker en bedre måte å finne de optimale parameterne på. GridSearchCV kan være kjedelig og veldig lang å trene hvis du passerer mange verdier. Søkeområdet vokser sammen med antall parametere. En foretrukket løsning er å bruke RandomizedSearchCV. Denne metoden består i å velge verdiene til hver hyperparameter etter hver iterasjon tilfeldig. For eksempel, hvis klassifisereren trenes over 1000 iterasjoner, blir 1000 kombinasjoner evaluert. Det fungerer mer eller mindre som. GridSearchCV

Du må importere xgboost. Hvis biblioteket ikke er installert, vennligst bruk pip3 install xgboost eller

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

In Jupyter miljø

Neste,

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

Det neste trinnet i denne Scikit Python opplæringen inkluderer å spesifisere parametrene som skal stilles inn. Du kan referere til den offisielle dokumentasjonen for å se alle parameterne som skal justeres. Av hensyn til Python Sklearn tutorial, du velger bare to hyperparametre med to verdier hver. XGBoost tar mye tid å trene, jo flere hyperparametre i rutenettet, jo lengre tid trenger du å vente.

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

Du konstruerer en ny pipeline med XGBoost-klassifiserer. Du velger å definere 600 estimatorer. Merk at n_estimators er en parameter du kan justere. En høy verdi kan føre til overmontering. Du kan prøve forskjellige verdier selv, men vær oppmerksom på at det kan ta timer. Du bruker standardverdien for de andre parameterne

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

Du kan forbedre kryssvalideringen med den Stratified K-Folds kryssvalidatoren. Du konstruerer bare tre folder her for å raskere beregningen, men redusere kvaliteten. Øk denne verdien til 5 eller 10 hjemme for å forbedre resultatene.

Du velger å trene modellen over fire iterasjoner.

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)

Det randomiserte søket er klart til bruk, du kan trene 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 poengsum enn den forrige logistiske regresjonen.

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)

Lag DNN med MLPClassifier i scikit-learn

Til slutt kan du trene en dyp læringsalgoritme med scikit-learn. Metoden er den samme som den andre klassifisereren. Klassifisereren er tilgjengelig på MLPClassifier.

from sklearn.neural_network import MLPClassifier

Du definerer følgende dyplæringsalgoritme:

  • Adam løser
  • Relu aktiveringsfunksjon
  • Alfa = 0.0001
  • batchstørrelse på 150
  • To skjulte lag med henholdsvis 100 og 50 nevroner
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 endre antall lag for å forbedre modellen

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

DNN regresjonsscore: 0.821253

LIME: Stol på modellen din

Nå som du har en god modell, trenger du et verktøy for å stole på den. Maskinlæring algoritmer, spesielt tilfeldig skog og nevrale nettverk, er kjent for å være black-box-algoritme. Si annerledes, det fungerer, men ingen vet hvorfor.

Tre forskere har kommet opp med et flott verktøy for å se hvordan datamaskinen gir en spådom. Avisen heter Why Should I Trust You?

De utviklet en algoritme kalt Lokale tolkbare modell-agnostiske forklaringer (LIME).

Ta et eksempel:

noen ganger vet du ikke om du kan stole på en maskinlæringsprediksjon:

En lege kan for eksempel ikke stole på en diagnose bare fordi en datamaskin sa det. Du må også vite om du kan stole på modellen før du setter den i produksjon.

Tenk deg at vi kan forstå hvorfor en klassifikator lager en prediksjon selv utrolig kompliserte modeller som nevrale nettverk, tilfeldige skoger eller svms med hvilken som helst kjerne

vil bli mer tilgjengelig for å stole på en prediksjon hvis vi kan forstå årsakene bak den. Fra eksemplet med legen, hvis modellen fortalte ham hvilke symptomer som er viktige du ville stole på, er det også lettere å finne ut om du ikke bør stole på modellen.

Lime kan fortelle deg hvilke funksjoner som påvirker avgjørelsene til klassifisereren

Dataklargjøring

De er et par ting du må endre for å kjøre LIME med python. Først av alt må du installere kalk i terminalen. Du kan bruke pip install lime

Lime bruker LimeTabularExplainer-objektet for å tilnærme modellen lokalt. Dette objektet krever:

  • et datasett i numpy-format
  • Navnet på funksjonene: funksjonsnavn
  • Navnet på klassene: klassenavn
  • Indeksen til kolonnen med kategoriske funksjoner: categorical_features
  • Navnet på gruppen for hver kategoriske funksjoner: categorical_names

Lag numpy togsett

Du kan kopiere og konvertere df_train fra pandaer til følelsesløs veldig lett

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

Få klassenavnet Etiketten er tilgjengelig med objektet unique(). Du bør se:

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

indeks av kolonnen med kategoriske funksjoner

Du kan bruke metoden du lener deg før for å få navnet på gruppen. Du koder etiketten med LabelEncoder. Du gjentar operasjonen på alle de kategoriske funksjonene.

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

Nå som datasettet er klart, kan du konstruere det forskjellige datasettet som vist i Scikit learn-eksempler nedenfor. Du transformerer faktisk dataene utenfor rørledningen for å unngå feil med LIME. Opplæringssettet i LimeTabularExplainer skal være en numpy array uten streng. Med metoden ovenfor har du allerede konvertert et treningsdatasett.

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 lage rørledningen med de optimale parameterne 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. Advarselen forklarer at du ikke trenger å opprette en etikettkoder før rørledningen. Hvis du ikke vil bruke LIME, kan du fint bruke metoden fra første del av Machine Learning with Scikit-learn-opplæringen. Ellers kan du fortsette med denne metoden, først opprette et kodet datasett, sett få den varme enkoderen i rørledningen.

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 bruker LIME i aksjon, la oss lage en numpy matrise med funksjonene til feil klassifisering. Du kan bruke den listen senere for å få en idé om hva som villeder klassifisereren.

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 lager en lambda-funksjon for å hente prediksjonen fra modellen med de nye dataene. Du trenger 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 dataramme 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)

La oss velge en tilfeldig husholdning fra testsettet og se modellprediksjonen og hvordan datamaskinen gjorde sitt 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 bruke forklaringen med explain_instance for å sjekke forklaringen bak modellen

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

Dataklargjøring

Vi kan se at klassifikatoren spådde husholdningen riktig. Inntekten er faktisk over 50k.

Det første vi kan si er at klassifisereren ikke er så sikker på de forutsagte sannsynlighetene. Maskinen spår at husholdningen har en inntekt over 50k med en sannsynlighet på 64%. Disse 64 % består av kapitalgevinst og ekteskap. Den blå fargen bidrar negativt til den positive klassen og den oransje linjen, positivt.

Klassifisereren er forvirret fordi kapitalgevinsten til denne husholdningen er null, mens kapitalgevinsten vanligvis er en god prediktor for formue. Dessuten jobber husholdningen mindre enn 40 timer i uken. Alder, yrke og kjønn bidrar positivt til klassifisereren.

Hvis sivilstatusen var singel, ville klassifikatoren ha spådd en inntekt under 50k (0.64-0.18 = 0.46)

Vi kan prøve med en annen husstand som har blitt feilklassifisert

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)

Dataklargjøring

Klassifisereren spådde en inntekt under 50k mens det er usant. Denne husholdningen virker rar. Den har ikke kapitalgevinst, og heller ikke kapitaltap. Han er skilt og er 60 år gammel, og det er et utdannet folk, dvs. utdanning_num > 12. I følge det overordnede mønsteret skal denne husstanden, som klassifisereren forklarer, få en inntekt under 50k.

Du prøver å leke med LIME. Du vil legge merke til grove feil fra klassifisereren.

Du kan sjekke GitHub til eieren av biblioteket. De gir ekstra dokumentasjon for bilde- og tekstklassifisering.

Sammendrag

Nedenfor er en liste over noen nyttige kommandoer med scikit learning-versjon >=0.20

lage tog-/testdatasett traineer splittes
Bygg en rørledning
velg kolonnen og bruk transformasjonen lage kolonnetransformator
type transformasjon
standardisere Standard Scaler
min maks MinMaxScaler
normal~~POS=TRUNC Normalisering
Beregn manglende verdi tilregne
Konverter kategorisk OneHotEncoder
Tilpass og transformer dataene passe_transform
Lag rørledningen make_pipeline
Grunnmodell
logistisk regresjon Logistisk regresjon
Xgboost XGBClassifier
Nevralt nett MLPClassifier
Rutenettsøk GridSearchCV
Randomisert søk RandomizedSearchCV