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.

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:
- Machine learning met scikit-learn
- 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:
- Standaardiseer de variabele: `StandardScaler()“
- 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)
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)
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 |