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.
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:
- Maskinlæring med scikit-learn
- 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:
- Standardiser variablen: `StandardScaler()“
- 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)
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)
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 |