Scikit-Learn-tutorial: installeren en Scikit-Learn-voorbeelden

Wat is Scikit-leren?

Scikit leren is een open-source Python bibliotheek voor machine learning. Het ondersteunt state-of-the-art algoritmen zoals KNN, XGBoost, random forest en SVM. Het is gebouwd op NumPy. Scikit-learn wordt veel gebruikt in Kaggle-competitie en door vooraanstaande technologiebedrijven. Het helpt bij preprocessing, dimensionaliteitsreductie (parameterselectie), classificatie, regressie, clustering en modelselectie.

Scikit-learn heeft de beste documentatie van alle open-sourcebibliotheken. Het biedt u een interactieve grafiek op https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Hoe Scikit Learn werkt
Hoe Scikit Learn werkt

Scikit-learn is niet erg moeilijk te gebruiken en levert uitstekende resultaten op. Scikit Learn ondersteunt echter geen parallelle berekeningen. Het is mogelijk om er een deep learning-algoritme mee te draaien, maar het is geen optimale oplossing, zeker niet als je weet hoe je TensorFlow moet gebruiken.

Scikit-learn downloaden en installeren

Nu in dit Python Scikit-learn tutorial, we zullen leren hoe je Scikit-learn kunt downloaden en installeren:

Optie 1: AWS

scikit-learn kan via AWS worden gebruikt. Alsjeblieft verwijzen De docker-installatiekopie waarop scikit-learn vooraf is geïnstalleerd.

Om de ontwikkelaarsversie te gebruiken, gebruikt u de opdracht in Jupyter

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

Optie 2: Mac of Windows gebruik van anaconda

Voor meer informatie over de installatie van Anaconda raadpleegt u https://www.guru99.com/download-install-tensorflow.html

Onlangs hebben de ontwikkelaars van scikit een ontwikkelingsversie uitgebracht die veelvoorkomende problemen met de huidige versie aanpakt. We vonden het handiger om de ontwikkelaarsversie te gebruiken in plaats van de huidige versie.

Scikit-learn installeren met Conda Environment

Als u scikit-learn hebt geïnstalleerd met de conda-omgeving, volgt u de stap om te updaten naar versie 0.20

Stap 1) Activeer de tensorflow-omgeving

source activate hello-tf

Stap 2) Verwijder scikit lean met het conda-commando

conda remove scikit-learn

Stap 3) Installeer de ontwikkelaarsversie.
Installeer de scikit learn-ontwikkelaarsversie samen met de benodigde bibliotheken.

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

NOTITIE: Windows gebruiker zal moeten installeren Microsoft Visual C++ 14. Je kunt het krijgen van hier

Scikit-Learn-voorbeeld met machine learning

Deze Scikit-tutorial is verdeeld in twee delen:

  1. Machine learning met scikit-learn
  2. Hoe u uw model kunt vertrouwen met LIME

In het eerste deel wordt gedetailleerd beschreven hoe u een pijplijn bouwt, een model maakt en de hyperparameters afstemt. In het tweede deel wordt de laatste stand van zaken op het gebied van modelselectie beschreven.

Stap 1) Importeer de gegevens

Tijdens deze Scikit-leertutorial gebruikt u de dataset voor volwassenen.

Voor een achtergrondinformatie over deze dataset, zie. Als u meer wilt weten over de beschrijvende statistieken, gebruik dan de duik- en overzichtstools.

Verwijzen deze tutorial leer meer over duiken en overzicht

Je importeert de dataset met Pandas. Merk op dat u het type continue variabelen in float-formaat moet converteren.

Deze dataset bevat acht categorische variabelen:

De categorische variabelen worden vermeld in CATE_FEATURES

  • werkklas
  • onderwijs
  • huwelijks-
  • bezetting
  • relatie
  • race
  • geslacht
  • geboorteland

bovendien zes continue variabelen:

De continue variabelen worden vermeld in CONTI_FEATURES

  • leeftijd
  • fnlwgt
  • onderwijs_num
  • kapitaal_winst
  • kapitaal_verlies
  • uren_week

Houd er rekening mee dat we de lijst met de hand invullen, zodat u een beter idee krijgt van welke kolommen we gebruiken. Een snellere manier om een ​​lijst met categorische of continue categorieën samen te stellen, is door het volgende te gebruiken:

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

Hier is de code om de gegevens te importeren:

# 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()
leeftijd fnlwgt onderwijs_num kapitaal_winst kapitaal_verlies uren_week
tellen 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
gemiddelde 38.581647 1.897784e + 05 10.080679 1077.648844 87.303830 40.437456
soa 13.640433 1.055500e + 05 2.572720 7385.292085 402.960219 12.347429
Min 17.000000 1.228500e + 04 1.000000 0.000000 0.000000 1.000000
25% 28.000000 1.178270e + 05 9.000000 0.000000 0.000000 40.000000
50% 37.000000 1.783560e + 05 10.000000 0.000000 0.000000 40.000000
75% 48.000000 2.370510e + 05 12.000000 0.000000 0.000000 45.000000
max 90.000000 1.484705e + 06 16.000000 99999.000000 4356.000000 99.000000

U kunt het aantal unieke waarden van de native_country-functies controleren. Je ziet dat er slechts één huishouden uit Nederland-Nederland komt. Dit huishouden geeft ons geen informatie, maar wel door een fout tijdens de training.

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

U kunt deze niet-informatieve rij uitsluiten van de gegevensset

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

Vervolgens slaat u de positie van de doorlopende objecten op in een lijst. U hebt deze nodig bij de volgende stap om de pijplijn te bouwen.

De onderstaande code loopt over alle kolomnamen in CONTI_FEATURES en haalt de locatie ervan op (dat wil zeggen het nummer) en voegt deze vervolgens toe aan een lijst met de naam 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]

De onderstaande code doet hetzelfde als hierboven, maar dan voor de categorische variabele. De onderstaande code herhaalt wat u eerder hebt gedaan, behalve met de categorische functies.

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

U kunt de dataset bekijken. Merk op dat elk categorisch kenmerk een string is. U kunt een model niet voeden met een stringwaarde. U moet de gegevensset transformeren met behulp van een dummyvariabele.

df_train.head(5)

In feite moet u voor elke groep in de functie één kolom maken. Eerst kunt u de onderstaande code uitvoeren om het totale aantal benodigde kolommen te berekenen.

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

De gehele dataset bevat 101 groepen zoals hierboven weergegeven. Bijvoorbeeld, de features van workclass hebben negen groepen. U kunt de naam van de groepen visualiseren met de volgende codes

unique() retourneert de unieke waarden van de categorische features.

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

Daarom bevat de trainingsgegevensset 101 + 7 kolommen. De laatste zeven kolommen zijn de doorlopende kenmerken.

Scikit-learn kan de conversie verzorgen. Het gebeurt in twee stappen:

  • Eerst moet u de tekenreeks naar ID converteren. De overheid heeft bijvoorbeeld ID 1, Self-emp-not-inc ID 2, enzovoort. De functie LabelEncoder doet dit voor u
  • Transponeer elke ID naar een nieuwe kolom. Zoals eerder vermeld, heeft de dataset 101 groeps-ID's. Daarom zullen er 101 kolommen zijn die alle categorische featuregroepen vastleggen. Scikit-learn heeft een functie genaamd OneHotEncoder die deze bewerking uitvoert

Stap 2) Maak de trein-/testset aan

Nu de dataset gereed is, kunnen we deze 80/20 splitsen.

80 procent voor de trainingsset en 20 procent voor de testset.

Je kunt train_test_split gebruiken. Het eerste argument is dat het dataframe de kenmerken is en het tweede argument is het labeldataframe. Met test_size kunt u de grootte van de testset opgeven.

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)

Stap 3) Bouw de pijpleiding

De pijplijn maakt het eenvoudiger om het model te voeden met consistente gegevens.

Het idee hierachter is om de ruwe data in een 'pijplijn' te plaatsen om bewerkingen uit te voeren.

Bijvoorbeeld, met de huidige dataset moet u de continue variabelen standaardiseren en de categorische data converteren. Merk op dat u elke bewerking binnen de pijplijn kunt uitvoeren. Bijvoorbeeld, als u 'NA's' in de dataset hebt, kunt u deze vervangen door het gemiddelde of de mediaan. U kunt ook nieuwe variabelen maken.

Jij hebt de keuze; codeer de twee processen hard of creëer een pijplijn. De eerste keuze kan leiden tot gegevenslekken en in de loop van de tijd tot inconsistenties. Een betere optie is om de pijpleiding te gebruiken.

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

De pijplijn voert twee bewerkingen uit voordat de logistieke classificator wordt gevoed:

  1. Standaardiseer de variabele: `StandardScaler()“
  2. Converteer de categorische kenmerken: OneHotEncoder(sparse=False)

U kunt de twee stappen uitvoeren met behulp van de make_column_transformer. Deze functie is niet beschikbaar in de huidige versie van scikit-learn (0.19). Met de huidige versie is het niet mogelijk om de label-encoder en één hot-encoder in de pijplijn uit te voeren. Het is een van de redenen waarom we besloten hebben om de ontwikkelaarsversie te gebruiken.

make_column_transformer is eenvoudig te gebruiken. U moet definiëren welke kolommen de transformatie moeten toepassen en welke transformatie moet worden uitgevoerd. Om bijvoorbeeld de continue feature te standaardiseren, kunt u het volgende doen:

  • conti_features, StandardScaler() binnen make_column_transformer.
    • conti_features: lijst met de continue variabele
    • StandardScaler: standaardiseer de variabele

Het object OneHotEncoder in make_column_transformer codeert automatisch het label.

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

U kunt testen of de pijplijn werkt met fit_transform. De dataset moet de volgende vorm hebben: 26048, 107

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

De datatransformator is klaar voor gebruik. U kunt de pijplijn maken met make_pipeline. Zodra de gegevens zijn getransformeerd, kunt u de logistieke regressie voeden.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Een model trainen met scikit-learn is triviaal. U moet de objectfit gebruiken, voorafgegaan door de pijplijn, dat wil zeggen: model. U kunt de nauwkeurigheid afdrukken met het scoreobject uit de scikit-learn-bibliotheek

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

Ten slotte kun je de klassen voorspellen met voorspellen_proba. Het retourneert de waarschijnlijkheid voor elke klasse. Merk op dat dit op één neerkomt.

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

Stap 4) Onze pijplijn gebruiken bij een rasterzoekopdracht

Het afstemmen van de hyperparameter (variabelen die de netwerkstructuur bepalen zoals verborgen eenheden) kan vervelend en vermoeiend zijn.

Eén manier om het model te evalueren zou kunnen zijn door de omvang van de trainingsset te veranderen en de prestaties te evalueren.

U kunt deze methode tien keer herhalen om de scorestatistieken te bekijken. Het is echter teveel werk.

In plaats daarvan biedt scikit-learn een functie voor het uitvoeren van parameterafstemming en kruisvalidatie.

Kruisvalidatie

Kruisvalidatie betekent dat tijdens de training de trainingsset n aantal keren in plooien wordt geschoven en vervolgens het model n keer wordt geëvalueerd. Als cv bijvoorbeeld is ingesteld op 10, wordt de trainingsset tien keer getraind en geëvalueerd. Bij elke ronde kiest de classificator willekeurig negen vouwen om het model te trainen, en de tiende vouw is bedoeld voor evaluatie.

Raster zoeken

Elke classificator heeft hyperparameters om af te stemmen. U kunt verschillende waarden proberen, of u kunt een parameterraster instellen. Als u naar de officiële website van scikit-learn gaat, ziet u dat de logistieke classificator verschillende parameters heeft om af te stemmen. Om de training sneller te laten verlopen, kies je ervoor om de C-parameter af te stemmen. Het controleert voor de regularisatieparameter. Het moet positief zijn. Een kleine waarde geeft meer gewicht aan de regularizer.

U kunt het object GridSearchCV gebruiken. U moet een woordenboek maken met de hyperparameters die u wilt afstemmen.

U vermeldt de hyperparameters, gevolgd door de waarden die u wilt proberen. Om bijvoorbeeld de C-parameter af te stemmen, gebruikt u:

  • 'logistischeregressie__C': [0.1, 1.0, 1.0]: De parameter wordt voorafgegaan door de naam, in kleine letters, van de classificator en twee onderstrepingstekens.

Het model probeert vier verschillende waarden: 0.001, 0.01, 0.1 en 1.

Je traint het model met 10 vouwen: cv=10

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

Je kunt het model trainen met behulp van GridSearchCV met de parameters gri en cv.

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

OUTPUT

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)

Om toegang te krijgen tot de beste parameters, gebruikt u best_params_

grid_clf.best_params_

OUTPUT

{'logisticregression__C': 1.0}

Nadat het model met vier verschillende regularisatiewaarden is getraind, is de optimale parameter

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

beste logistische regressie uit rasterzoekopdracht: 0.850891

Om toegang te krijgen tot de voorspelde kansen:

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

Laten we Scikit-learn-voorbeelden proberen om een ​​van de beste classificatoren op de markt te trainen. XGBoost is een verbetering ten opzichte van het willekeurige forest. De theoretische achtergrond van de classificator valt buiten het bestek hiervan Python Scikit-tutorial. Houd er rekening mee dat XGBoost veel Kaggle-competities heeft gewonnen. Met een gemiddelde datasetgrootte kan het net zo goed presteren als een deep learning-algoritme of zelfs beter.

De classificator is een uitdaging om te trainen, omdat er een groot aantal parameters moet worden afgestemd. U kunt uiteraard GridSearchCV gebruiken om de parameter voor u te kiezen.

Laten we in plaats daarvan kijken hoe we een betere manier kunnen gebruiken om de optimale parameters te vinden. GridSearchCV kan vervelend en erg lang zijn om te trainen als u veel waarden doorstaat. De zoekruimte groeit mee met het aantal parameters. Een oplossing die de voorkeur verdient is het gebruik van RandomizedSearchCV. Deze methode bestaat uit het willekeurig kiezen van de waarden van elke hyperparameter na elke iteratie. Als de classificator bijvoorbeeld over 1000 iteraties wordt getraind, worden 1000 combinaties geëvalueerd. Het werkt min of meer als. GridSearchCV

U moet xgboost importeren. Als de bibliotheek niet is geïnstalleerd, gebruik dan pip3 install xgboost of

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

In Jupyter omgeving houden

Vervolgens

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

De volgende stap in deze Scikit Python de tutorial bevat het specificeren van de af te stemmen parameters. U kunt de officiële documentatie raadplegen om alle af te stemmen parameters te bekijken. Terwille van de Python In de Sklearn-tutorial kiest u slechts twee hyperparameters met elk twee waarden. XGBoost kost veel tijd om te trainen, hoe meer hyperparameters in het raster, hoe langer je moet wachten.

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

U construeert een nieuwe pijplijn met XGBoost-classifier. U kiest ervoor om 600 estimators te definiëren. Let op dat n_estimators een parameter zijn die u kunt afstemmen. Een hoge waarde kan leiden tot overfitting. U kunt zelf verschillende waarden proberen, maar wees u ervan bewust dat dit uren kan duren. U gebruikt de standaardwaarde voor de andere parameters

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

U kunt de kruisvalidatie verbeteren met de Stratified K-Folds kruisvalidator. Je construeert hier slechts drie vouwen om de berekening te versnellen, maar de kwaliteit te verlagen. Verhoog deze waarde thuis naar 5 of 10 om de resultaten te verbeteren.

U kiest ervoor om het model in vier iteraties te trainen.

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)

De gerandomiseerde zoekopdracht is klaar voor gebruik, u kunt het model trainen

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

Zoals u kunt zien, scoort XGBoost beter dan de vorige logistische regressie.

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)

Maak DNN met MLPClassifier in scikit-learn

Ten slotte kun je met scikit-learn een deep learning-algoritme trainen. De methode is hetzelfde als de andere classificator. De classificator is beschikbaar op MLPClassifier.

from sklearn.neural_network import MLPClassifier

U definieert het volgende deep learning-algoritme:

  • Adam-oplosser
  • Relu-activeringsfunctie
  • Alfa = 0.0001
  • batchgrootte van 150
  • Twee verborgen lagen met respectievelijk 100 en 50 neuronen
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

U kunt het aantal lagen wijzigen om het model te verbeteren

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

DNN-regressiescore: 0.821253

LIME: Vertrouw op je model

Nu je een goed model hebt, heb je een hulpmiddel nodig om erop te vertrouwen. machine learning algoritme, met name random forest en neural network, staan ​​bekend als black-box algoritmes. Anders gezegd, het werkt, maar niemand weet waarom.

Drie onderzoekers hebben een geweldig hulpmiddel bedacht om te kijken hoe de computer een voorspelling doet. Het artikel heet Waarom zou ik je vertrouwen?

Ze ontwikkelden een algoritme genaamd Lokaal interpreteerbare model-agnostische verklaringen (LIME).

Neem een ​​voorbeeld:

soms weet je niet of je een machine-learning voorspelling kunt vertrouwen:

Een arts kan bijvoorbeeld een diagnose niet vertrouwen alleen maar omdat een computer dat zegt. U moet ook weten of u het model kunt vertrouwen voordat u het in productie neemt.

Stel je voor dat we kunnen begrijpen waarom welke classificator dan ook een voorspelling doet, zelfs ongelooflijk ingewikkelde modellen zoals neurale netwerken, willekeurige forests of svms met welke kernel dan ook

Het zal toegankelijker worden om op een voorspelling te vertrouwen als we de redenen erachter kunnen begrijpen. Uit het voorbeeld met de dokter: als het model hem vertelde welke symptomen essentieel zijn, zou je hem vertrouwen, het is ook gemakkelijker om erachter te komen of je het model niet zou moeten vertrouwen.

Lime kan u vertellen welke kenmerken van invloed zijn op de beslissingen van de classificator

Data voorbereiding

Er zijn een paar dingen die je moet veranderen om LIME mee te kunnen gebruiken python. Allereerst moet u kalk in de terminal installeren. Je kunt pip install kalk gebruiken

Lime maakt gebruik van het LimeTabularExplainer-object om het model lokaal te benaderen. Dit object vereist:

  • een dataset in numpy-formaat
  • De naam van de features: feature_names
  • De naam van de klassen: class_names
  • De index van de kolom met categorische kenmerken: categorical_features
  • De naam van de groep voor elk categorisch kenmerk: categorische_namen

Maak een numpy treinset

U kunt df_train kopiëren en converteren van panda's naar numpy Heel makkelijk

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

Haal de klassenaam op Het label is toegankelijk met het object unique(). Je zou moeten zien:

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

index van de kolom met categorische kenmerken

U kunt de methode die u eerder hebt geleerd gebruiken om de naam van de groep te krijgen. U codeert het label met LabelEncoder. U herhaalt de bewerking op alle categorische kenmerken.

## 
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 de dataset gereed is, kunt u de verschillende dataset samenstellen, zoals weergegeven in de onderstaande Scikit-leervoorbeelden. Je transformeert de data feitelijk buiten de pipeline om fouten met LIME te voorkomen. De trainingsset in LimeTabularExplainer moet een numpy-array zonder string zijn. Met de bovenstaande methode heeft u al een trainingsgegevensset geconverteerd.

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)

U kunt de pijplijn maken met de optimale parameters van 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))])

U krijgt een waarschuwing. De waarschuwing legt uit dat u geen label-encoder hoeft te maken vóór de pijplijn. Als u LIME niet wilt gebruiken, kunt u de methode uit het eerste deel van de Machine Learning met Scikit-learn tutorial gebruiken. Anders kunt u deze methode aanhouden, eerst een gecodeerde dataset maken, de hot one encoder binnen de pijplijn instellen.

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)

Voordat we LIME in actie gaan gebruiken, maken we een numpy array met de kenmerken van de verkeerde classificatie. U kunt die lijst later gebruiken om een ​​idee te krijgen van wat de classifier misleidt.

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)

U maakt een lambda-functie om de voorspelling uit het model op te halen met de nieuwe gegevens. Je zult het binnenkort nodig hebben.

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

U converteert het pandas-dataframe naar een 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)

Laten we een willekeurig huishouden uit de testset kiezen en de modelvoorspelling bekijken en zien hoe de computer zijn keuze heeft gemaakt.

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

U kunt de uitleg met uitleg_instance gebruiken om de uitleg achter het model te controleren

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

Data voorbereiding

We kunnen zien dat de classificator het huishouden correct heeft voorspeld. Het inkomen ligt inderdaad boven de 50.

Het eerste wat we kunnen zeggen is dat de classificator niet zo zeker is over de voorspelde waarschijnlijkheid. De machine voorspelt dat het huishouden een inkomen heeft van meer dan 50k met een waarschijnlijkheid van 64%. Deze 64% bestaat uit vermogenswinst en huwelijksvermogen. De blauwe kleur draagt ​​negatief bij aan de positieve klasse en de oranje lijn positief.

De classifier is verwarrend omdat de kapitaalwinst van dit huishouden nul is, terwijl de kapitaalwinst doorgaans een goede voorspeller is van rijkdom. Bovendien werkt het huishouden minder dan 40 uur per week. Leeftijd, beroep en geslacht dragen positief bij aan de classifier.

Als de burgerlijke staat alleenstaand was, zou de classificator een inkomen onder de 50 hebben voorspeld (0.64-0.18 = 0.46)

We kunnen het proberen met een ander huishouden dat verkeerd is geclassificeerd

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)

Data voorbereiding

De classificator voorspelde een inkomen onder de 50, terwijl dit niet waar is. Dit huishouden lijkt vreemd. Er is geen sprake van een meerwaarde, noch van een kapitaalverlies. Hij is gescheiden en is 60 jaar oud, en het is een goed opgeleid volk, dwz opleidingsgetal > 12. Volgens het algemene patroon zou dit huishouden, zoals uitgelegd door de classificator, een inkomen van minder dan 50 moeten krijgen.

Je probeert met LIME te spelen. U zult grove fouten van de classificator opmerken.

U kunt de GitHub van de eigenaar van de bibliotheek controleren. Ze bieden extra documentatie voor beeld- en tekstclassificatie.

Samenvatting

Hieronder vindt u een lijst met enkele nuttige opdrachten met scikit learn-versie >=0.20

maak een trein-/testgegevensset stagiaires verdeeld
Bouw een pijplijn
selecteer de kolom en pas de transformatie toe maakkolomtransformator
soort transformatie
normaliseren Standaardscaler
minimaal maximaal MinMaxScaler
normaliseren Normalizer
Impliceer de ontbrekende waarde toerekenen
Converteer categorisch OneHotEncoder
Pas de gegevens aan en transformeer ze fit_transform
Maak de pijpleiding make_pipeline
Basismodel
logistische regressie Logistische regressie
XGBoost XGBClassifier
neuraal net MLP-classificatie
Raster zoeken RasterZoekenCV
Gerandomiseerde zoekopdracht GerandomiseerdZoekenCV