Tutorial Scikit-Learn: Cum se instalează și exemple Scikit-Learn

Ce este Scikit-learn?

Scikit-învață este un open-source Python bibliotecă pentru învățarea automată. Acceptă algoritmi de ultimă generație, cum ar fi KNN, XGBoost, pădure aleatoare și SVM. Este construit pe NumPy. Scikit-learn este utilizat pe scară largă în competiția Kaggle, precum și în companiile de tehnologie proeminente. Ajută la preprocesare, reducerea dimensionalității (selectarea parametrilor), clasificarea, regresia, gruparea și selecția modelului.

Scikit-learn are cea mai bună documentație dintre toate bibliotecile open-source. Vă oferă o diagramă interactivă la https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Cum funcționează Scikit Learn
Cum funcționează Scikit Learn

Scikit-learn nu este foarte dificil de utilizat și oferă rezultate excelente. Cu toate acestea, scikit Learn nu acceptă calcule paralele. Este posibil să rulați un algoritm de învățare profundă cu acesta, dar nu este o soluție optimă, mai ales dacă știți să utilizați TensorFlow.

Cum să descărcați și să instalați Scikit-learn

Acum în asta Python Tutorial Scikit-learn, vom învăța cum să descărcați și să instalați Scikit-learn:

Opțiunea 1: AWS

scikit-learn poate fi utilizat pe AWS. Vă rog trimite Imaginea docker care are scikit-learn preinstalat.

Pentru a utiliza versiunea de dezvoltator, utilizați comanda în Jupyter

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

Opțiunea 2: Mac sau Windows folosind Anaconda

Pentru a afla despre instalarea Anaconda, consultați https://www.guru99.com/download-install-tensorflow.html

Recent, dezvoltatorii scikit au lansat o versiune de dezvoltare care abordează problema comună cu care se confruntă versiunea actuală. Am considerat că este mai convenabil să folosim versiunea de dezvoltator în loc de versiunea actuală.

Cum se instalează scikit-learn cu Conda Environment

Dacă ați instalat scikit-learn cu mediul conda, vă rugăm să urmați pasul pentru a actualiza la versiunea 0.20

Pas 1) Activați mediul tensorflow

source activate hello-tf

Pas 2) Eliminați scikit lean folosind comanda conda

conda remove scikit-learn

Pas 3) Instalați versiunea de dezvoltator.
Instalați versiunea de dezvoltator scikit Learn împreună cu bibliotecile necesare.

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

NOTĂ: Windows utilizatorul va trebui să instaleze Microsoft Vizual C++ 14. Îl poți obține de la aici

Scikit-Learn Exemplu cu Machine Learning

Acest tutorial Scikit este împărțit în două părți:

  1. Învățare automată cu scikit-learn
  2. Cum să ai încredere în modelul tău cu LIME

Prima parte detaliază cum să construiți o conductă, să creați un model și să reglați hiperparametrii, în timp ce a doua parte oferă stadiul tehnicii în ceea ce privește selecția modelului.

Pasul 1) Importați datele

În timpul acestui tutorial de învățare Scikit, veți folosi setul de date pentru adulți.

Pentru informații despre acest set de date, consultați Dacă sunteți interesat să aflați mai multe despre statisticile descriptive, vă rugăm să utilizați instrumentele Dive și Overview.

Trimite acest tutorial aflați mai multe despre scufundare și prezentare generală

Importați setul de date cu Pandas. Rețineți că trebuie să convertiți tipul variabilelor continue în format flotant.

Acest set de date include opt variabile categoriale:

Variabilele categoriale sunt listate în CATE_FEATURES

  • clasa de lucru
  • educaţie
  • marital
  • ocupație
  • relaţie
  • rasă
  • sex
  • tara de origine

în plus, șase variabile continue:

Variabilele continue sunt listate în CONTI_FEATURES

  • vârstă
  • fnlwgt
  • educație_num
  • câștig de capital
  • pierdere_capital
  • ore_săptămână

Rețineți că completăm lista manual, astfel încât să aveți o idee mai bună despre ce coloane folosim. O modalitate mai rapidă de a construi o listă de categorii categorice sau continue este să utilizați:

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

Iată codul pentru a importa datele:

# 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()
vârstă fnlwgt educație_num câștig de capital pierdere_capital ore_săptămână
conta 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
însemna 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
minute 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

Puteți verifica numărul de valori unice ale caracteristicilor native_country. Puteți vedea că o singură gospodărie provine din Olanda-Olanda. Această gospodărie nu ne va aduce nicio informație, dar o va face printr-o eroare în timpul antrenamentului.

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

Puteți exclude acest rând neinformativ din setul de date

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

Apoi, stocați poziția caracteristicilor continue într-o listă. Veți avea nevoie de el în următorul pas pentru a construi conducta.

Codul de mai jos va trece peste numele tuturor coloanelor din CONTI_FEATURES și va obține locația acestuia (adică, numărul) și apoi îl va adăuga la o listă numită 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]

Codul de mai jos face aceeași treabă ca mai sus, dar pentru variabila categorială. Codul de mai jos repetă ceea ce ați făcut anterior, cu excepția caracteristicilor categoriale.

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

Puteți arunca o privire la setul de date. Rețineți că fiecare caracteristică categorială este un șir. Nu puteți alimenta un model cu o valoare șir. Trebuie să transformați setul de date folosind o variabilă inactivă.

df_train.head(5)

De fapt, trebuie să creați o coloană pentru fiecare grup din caracteristică. În primul rând, puteți rula codul de mai jos pentru a calcula cantitatea totală de coloane necesare.

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

Întregul set de date conține 101 grupuri, așa cum se arată mai sus. De exemplu, caracteristicile clasei de muncă au nouă grupuri. Puteți vizualiza numele grupurilor cu următoarele coduri

unique() returnează valorile unice ale caracteristicilor categoriale.

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

Prin urmare, setul de date de antrenament va conține 101 + 7 coloane. Ultimele șapte coloane sunt caracteristicile continue.

Scikit-learn se poate ocupa de conversie. Se realizează în doi pași:

  • Mai întâi, trebuie să convertiți șirul în ID. De exemplu, State-gov va avea ID 1, Self-emp-not-inc ID 2 și așa mai departe. Funcția LabelEncoder face acest lucru pentru tine
  • Transpuneți fiecare ID într-o coloană nouă. După cum sa menționat anterior, setul de date are 101 ID-uri de grup. Prin urmare, vor exista 101 coloane care captează toate grupurile de caracteristici categorice. Scikit-learn are o funcție numită OneHotEncoder care efectuează această operație

Pasul 2) Creați trenul/setul de testare

Acum că setul de date este gata, îl putem împărți 80/20.

80% pentru setul de antrenament și 20% pentru setul de testare.

Puteți folosi train_test_split. Primul argument este cadrul de date este caracteristicile și al doilea argument este cadrul de date eticheta. Puteți specifica dimensiunea setului de testare cu 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)

Pasul 3) Construiți conducta

Conducta facilitează alimentarea modelului cu date consistente.

Ideea din spate este de a pune datele brute într-o „conductă” pentru a efectua operațiuni.

De exemplu, cu setul de date curent, trebuie să standardizați variabilele continue și să convertiți datele categorice. Rețineți că puteți efectua orice operațiune în interiorul conductei. De exemplu, dacă aveți „NA” în setul de date, le puteți înlocui cu media sau mediana. De asemenea, puteți crea variabile noi.

Ai de ales; codificați cele două procese sau creați o conductă. Prima alegere poate duce la scurgeri de date și poate crea inconsecvențe în timp. O opțiune mai bună este utilizarea conductei.

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

Conducta va efectua două operațiuni înainte de a alimenta clasificatorul logistic:

  1. Standardizați variabila: „StandardScaler()“
  2. Convertiți caracteristicile categoriale: OneHotEncoder(sparse=False)

Puteți efectua cei doi pași folosind make_column_transformer. Această funcție nu este disponibilă în versiunea curentă a scikit-learn (0.19). Cu versiunea curentă nu este posibil să se realizeze codificatorul de etichetă și un codificator fierbinte în conductă. Acesta este unul dintre motivele pentru care am decis să folosim versiunea pentru dezvoltatori.

make_column_transformer este ușor de utilizat. Trebuie să definiți ce coloane să aplicați transformarea și ce transformare să operați. De exemplu, pentru a standardiza caracteristica continuă, puteți face:

  • conti_features, StandardScaler() în interiorul make_column_transformer.
    • conti_features: listă cu variabila continuă
    • StandardScaler: standardizați variabila

Obiectul OneHotEncoder din make_column_transformer codifică automat eticheta.

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

Puteți testa dacă conducta funcționează cu fit_transform. Setul de date ar trebui să aibă următoarea formă: 26048, 107

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

Transformatorul de date este gata de utilizare. Puteți crea conducta cu make_pipeline. Odată ce datele sunt transformate, puteți alimenta regresia logistică.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Antrenarea unui model cu scikit-learn este banala. Trebuie să utilizați potrivirea obiectului precedată de conductă, adică modelul. Puteți imprima acuratețea cu obiectul scor din biblioteca scikit-learn

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

În cele din urmă, puteți prezice clasele cu predict_proba. Returnează probabilitatea pentru fiecare clasă. Rețineți că se însumează la unu.

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

Pasul 4) Utilizarea conductei noastre într-o căutare în grilă

Reglarea hiperparametrului (variabilele care determină structura rețelei precum unitățile ascunse) poate fi obositoare și obositoare.

O modalitate de a evalua modelul ar putea fi schimbarea dimensiunii setului de antrenament și evaluarea performanțelor.

Puteți repeta această metodă de zece ori pentru a vedea valorile scorului. Cu toate acestea, este prea multă muncă.

În schimb, scikit-learn oferă o funcție pentru a efectua reglarea parametrilor și validarea încrucișată.

Validare încrucișată

Validarea încrucișată înseamnă în timpul antrenamentului, setul de antrenament este alunecat de n număr de ori în pliuri și apoi evaluează modelul n timp. De exemplu, dacă cv este setat la 10, setul de antrenament este antrenat și evaluează de zece ori. La fiecare rundă, clasificatorul alege aleatoriu nouă pliuri pentru a antrena modelul, iar a zecea ori este destinată evaluării.

Căutare în grilă

Fiecare clasificator are hiperparametri de reglat. Puteți încerca valori diferite sau puteți seta o grilă de parametri. Dacă accesați site-ul oficial scikit-learn, puteți vedea că clasificatorul logistic are diferiți parametri de reglat. Pentru a face antrenamentul mai rapid, alegeți să reglați parametrul C. Controlează parametrul de regularizare. Ar trebui să fie pozitiv. O valoare mică conferă mai multă greutate regulatorului.

Puteți utiliza obiectul GridSearchCV. Trebuie să creați un dicționar care să conțină hiperparametrii de reglat.

Listați hiperparametrii urmați de valorile pe care doriți să le încercați. De exemplu, pentru a regla parametrul C, utilizați:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: Parametrul este precedat de numele, în litere mici, a clasificatorului și două litere de subliniere.

Modelul va încerca patru valori diferite: 0.001, 0.01, 0.1 și 1.

Antrenați modelul folosind 10 pliuri: cv=10

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

Puteți antrena modelul folosind GridSearchCV cu parametrul gri și cv.

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

REZULTATE

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)

Pentru a accesa cei mai buni parametri, utilizați best_params_

grid_clf.best_params_

REZULTATE

{'logisticregression__C': 1.0}

După antrenarea modelului cu patru valori de regularizare diferite, parametrul optim este

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

cea mai bună regresie logistică din căutarea în grilă: 0.850891

Pentru a accesa probabilitățile prezise:

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

Model XGBoost cu scikit-learn

Să încercăm exemple Scikit-learn pentru a instrui unul dintre cei mai buni clasificatori de pe piață. XGBoost este o îmbunătățire față de pădurea aleatorie. Fundalul teoretic al clasificatorului în afara domeniului de aplicare al acestui Python Tutorial Scikit. Rețineți că, XGBoost a câștigat o mulțime de competiții de kaggle. Cu o dimensiune medie a setului de date, poate funcționa la fel de bine ca un algoritm de învățare profundă sau chiar mai bine.

Clasificatorul este dificil de antrenat, deoarece are un număr mare de parametri de reglat. Puteți, desigur, să utilizați GridSearchCV pentru a alege parametrul pentru dvs.

În schimb, să vedem cum să folosim o modalitate mai bună de a găsi parametrii optimi. GridSearchCV poate fi plictisitor și foarte lung de antrenat dacă treci de multe valori. Spațiul de căutare crește odată cu numărul de parametri. O soluție preferabilă este utilizarea RandomizedSearchCV. Această metodă constă în alegerea aleatorie a valorilor fiecărui hiperparametru după fiecare iterație. De exemplu, dacă clasificatorul este antrenat peste 1000 de iterații, atunci sunt evaluate 1000 de combinații. Funcționează mai mult sau mai puțin ca. GridSearchCV

Trebuie să importați xgboost. Dacă biblioteca nu este instalată, vă rugăm să utilizați pip3 install xgboost sau

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

In Jupyter mediu inconjurator

În continuare,

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

Următorul pas în acest Scikit Python tutorialul include specificarea parametrilor de reglat. Puteți consulta documentația oficială pentru a vedea toți parametrii de reglat. De dragul Python Tutorial Sklearn, alegeți doar doi hiperparametri cu câte două valori fiecare. XGBoost durează mult timp pentru a se antrena, cu cât sunt mai mulți hiperparametri în grilă, cu atât trebuie să așteptați mai mult.

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

Construiți o nouă conductă cu clasificatorul XGBoost. Alegeți să definiți 600 de estimatori. Rețineți că n_estimators sunt un parametru pe care îl puteți regla. O valoare mare poate duce la supraadaptare. Puteți încerca singur valori diferite, dar fiți conștienți că poate dura ore. Utilizați valoarea implicită pentru ceilalți parametri

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

Puteți îmbunătăți validarea încrucișată cu validatorul încrucișat Stratified K-Folds. Construiți doar trei ori aici pentru a accelera calculul, dar pentru a reduce calitatea. Creșteți această valoare la 5 sau 10 acasă pentru a îmbunătăți rezultatele.

Alegeți să antrenați modelul în patru iterații.

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)

Căutarea randomizată este gata de utilizare, puteți antrena modelul

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

După cum puteți vedea, XGBoost are un scor mai bun decât regresia logistică anterioară.

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)

Creați DNN cu MLPClassifier în scikit-learn

În cele din urmă, puteți antrena un algoritm de învățare profundă cu scikit-learn. Metoda este aceeași ca și celălalt clasificator. Clasificatorul este disponibil la MLPClassifier.

from sklearn.neural_network import MLPClassifier

Definiți următorul algoritm de învățare profundă:

  • Adam rezolvator
  • Funcția de activare Relu
  • Alfa = 0.0001
  • dimensiunea lotului de 150
  • Două straturi ascunse cu 100 și, respectiv, 50 de neuroni
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Puteți modifica numărul de straturi pentru a îmbunătăți modelul

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

Scorul de regresie DNN: 0.821253

LIME: Ai încredere în modelul tău

Acum că ai un model bun, ai nevoie de un instrument în care să ai încredere în el. Invatare mecanica algoritmul, în special pădurile aleatorii și rețelele neuronale, sunt cunoscute a fi algoritm cutie neagră. Spune altfel, funcționează, dar nimeni nu știe de ce.

Trei cercetători au venit cu un instrument excelent pentru a vedea cum computerul face o predicție. Lucrarea se numește De ce ar trebui să am încredere în tine?

Ei au dezvoltat un algoritm numit Explicații locale interpretabile pentru model-agnostic (LIME).

Luați un exemplu:

uneori nu știi dacă poți avea încredere într-o predicție de învățare automată:

Un medic, de exemplu, nu poate avea încredere într-un diagnostic doar pentru că așa spune un computer. De asemenea, trebuie să știți dacă puteți avea încredere în model înainte de a-l pune în producție.

Imaginați-vă că putem înțelege de ce orice clasificator face o predicție chiar și modele incredibil de complicate, cum ar fi rețele neuronale, păduri aleatorii sau svm-uri cu orice nucleu

va deveni mai accesibil să avem încredere într-o predicție dacă putem înțelege motivele din spatele acesteia. Din exemplul cu medicul, dacă modelul i-a spus ce simptome sunt esențiale ai avea încredere în el, este și mai ușor să-ți dai seama dacă nu ar trebui să ai încredere în model.

Lime vă poate spune ce caracteristici afectează deciziile clasificatorului

Pregătirea datelor

Sunt câteva lucruri pe care trebuie să le schimbi pentru a rula LIME piton. În primul rând, trebuie să instalați var în terminal. Puteți folosi pip install var

Lime folosește obiectul LimeTabularExplainer pentru a aproxima modelul la nivel local. Acest obiect necesită:

  • un set de date în format numpy
  • Numele caracteristicilor: feature_names
  • Numele claselor: class_names
  • Indexul coloanei caracteristicilor categoriale: caracteristici_categorice
  • Numele grupului pentru fiecare caracteristică categorială: nume_categorice

Creați un set de tren numpy

Puteți copia și converti df_train din panda în NumPy foarte usor

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

Obțineți numele clasei Eticheta este accesibilă cu obiectul unique(). Ar trebui sa vezi:

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

indicele coloanei trăsăturilor categoriale

Puteți folosi metoda pe care o înclinați înainte pentru a obține numele grupului. Codificați eticheta cu LabelEncoder. Repetați operația pe toate caracteristicile categoriale.

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

Acum că setul de date este gata, puteți construi setul de date diferit, așa cum se arată în exemplele de mai jos Scikit Learn. De fapt, transformați datele în afara conductei pentru a evita erorile cu LIME. Setul de antrenament din LimeTabularExplainer ar trebui să fie o matrice numpy fără șir. Cu metoda de mai sus, aveți deja un set de date de antrenament convertit.

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)

Puteți realiza conducta cu parametrii optimi din 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))])

Primești un avertisment. Avertismentul explică faptul că nu trebuie să creați un codificator de etichetă înaintea conductei. Dacă nu doriți să utilizați LIME, este bine să utilizați metoda din prima parte a tutorialului Machine Learning cu Scikit-learn. În caz contrar, puteți păstra această metodă, creați mai întâi un set de date codificat, setați obțineți codificatorul fierbinte în conductă.

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)

Înainte de a folosi LIME în acțiune, să creăm o matrice numpy cu caracteristicile clasificării greșite. Puteți folosi acea listă mai târziu pentru a vă face o idee despre ceea ce induce în eroare clasificatorul.

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)

Creați o funcție lambda pentru a prelua predicția din model cu noile date. Veți avea nevoie de el în curând.

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

Convertiți cadrul de date panda în matrice numpy

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)

Să alegem o gospodărie aleatorie din setul de testare și să vedem predicția modelului și modul în care computerul a făcut alegerea sa.

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

Puteți folosi explicația cu explic_instance pentru a verifica explicația din spatele modelului

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

Pregătirea datelor

Putem vedea că clasificatorul a prezis corect gospodăria. Venitul este, într-adevăr, peste 50k.

Primul lucru pe care îl putem spune este că clasificatorul nu este atât de sigur cu privire la probabilitățile prezise. Aparatul prezice că gospodăria are un venit peste 50k cu o probabilitate de 64%. Acest 64% este alcătuit din câștig de capital și conjugal. Culoarea albastră contribuie negativ la clasa pozitivă, iar linia portocalie, pozitiv.

Clasificatorul este confuz deoarece câștigul de capital al acestei gospodării este nul, în timp ce câștigul de capital este de obicei un bun predictor al bogăției. În plus, gospodăria lucrează mai puțin de 40 de ore pe săptămână. Vârsta, ocupația și sexul contribuie pozitiv la clasificare.

Dacă starea civilă ar fi fost singură, clasificatorul ar fi prezis un venit sub 50k (0.64-0.18 = 0.46)

Putem încerca cu o altă gospodărie care a fost clasificată greșit

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)

Pregătirea datelor

Clasificatorul a prezis un venit sub 50k, în timp ce este neadevărat. Gospodăria asta pare ciudată. Nu are câștig de capital, nici pierdere de capital. El este divorțat și are 60 de ani și este un popor educat, adică education_num > 12. Conform modelului general, această gospodărie ar trebui, așa cum explică clasificatorul, să obțină un venit sub 50k.

Încercați să vă jucați cu LIME. Veți observa greșeli grave de la clasificator.

Puteți verifica GitHub-ul proprietarului bibliotecii. Acestea oferă documentație suplimentară pentru clasificarea imaginilor și a textului.

Rezumat

Mai jos este o listă cu câteva comenzi utile cu versiunea scikit learn >=0.20

creați setul de date tren/test stagiarii s-au împărțit
Construiți o conductă
selectați coloana și aplicați transformarea makecolumntransformer
tip de transformare
standardiza StandardScaler
minim maxim MinMaxScaler
normaliza Normalizator
Imputați valoarea lipsă imputa
Convertiți categoric OneHotEncoder
Potriviți și transformați datele potrivi_transforma
Faceți conducta make_pipeline
Model de bază
regresie logistică Regresie logistică
XGBoost XGBClassifier
Rețea neuronală Clasificator MLPC
Căutare în grilă GridSearchCV
Căutare aleatorie RandomizedSearchCV