Підручник Scikit-Learn: як встановити та приклади Scikit-Learn

Що таке Scikit-learn?

Scikit-Learn є відкритим кодом Python бібліотека для машинного навчання. Він підтримує найсучасніші алгоритми, такі як KNN, XGBoost, випадковий ліс і SVM. Він створений на основі NumPy. Scikit-learn широко використовується в конкуренції Kaggle, а також у відомих технологічних компаніях. Це допомагає в попередній обробці, зменшенні розмірності (вибір параметрів), класифікації, регресії, кластеризації та виборі моделі.

Scikit-learn має найкращу документацію з усіх відкритих бібліотек. Він надає вам інтерактивну діаграму на https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Як працює Scikit Learn
Як працює Scikit Learn

Scikit-learn не дуже складний у використанні та забезпечує чудові результати. Однак scikit learn не підтримує паралельні обчислення. З ним можна запустити алгоритм глибокого навчання, але це не оптимальне рішення, особливо якщо ви знаєте, як використовувати TensorFlow.

Як завантажити та встановити Scikit-learn

Тепер у цьому Python Підручник Scikit-learn, ми навчимося завантажувати та інсталювати Scikit-learn:

Варіант 1: AWS

scikit-learn можна використовувати над AWS. Будь ласка послатися Образ докера, у якому попередньо встановлено scikit-learn.

Щоб використовувати версію для розробника, використовуйте команду in Jupyter

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

Варіант 2: Mac або Windows за допомогою Anaconda

Щоб дізнатися про встановлення Anaconda, див https://www.guru99.com/download-install-tensorflow.html

Нещодавно розробники scikit випустили версію для розробки, яка вирішує поширену проблему, з якою стикається поточна версія. Нам було зручніше використовувати версію розробника замість поточної версії.

Як встановити scikit-learn за допомогою Conda Environment

Якщо ви встановили scikit-learn із середовищем conda, виконайте кроки для оновлення до версії 0.20

Крок 1) Активуйте середовище tensorflow

source activate hello-tf

Крок 2) Видаліть scikit lean за допомогою команди conda

conda remove scikit-learn

Крок 3) Встановити версію для розробника.
Встановіть версію для розробника scikit learn разом із необхідними бібліотеками.

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

ПРИМІТКА: Windows користувачу потрібно буде встановити Microsoft Візуальний C++ 14. Ви можете отримати це з тут

Приклад Scikit-Learn із машинним навчанням

Цей підручник Scikit розділений на дві частини:

  1. Машинне навчання за допомогою scikit-learn
  2. Як довіряти своїй моделі LIME

У першій частині детально описано, як побудувати конвеєр, створити модель і налаштувати гіперпараметри, тоді як у другій частині наведено найсучасніші відомості щодо вибору моделі.

Крок 1) Імпортуйте дані

Під час цього уроку вивчення Scikit ви будете використовувати набір даних для дорослих.

Докладніше про цей набір даних див. Якщо вам цікаво дізнатися більше про описову статистику, скористайтеся інструментами Dive та Overview.

Ставитися цей підручник дізнайтеся більше про Dive та Overview

Ви імпортуєте набір даних за допомогою Pandas. Зверніть увагу, що вам потрібно перетворити тип безперервних змінних у форматі з плаваючою точкою.

Цей набір даних включає вісім категоріальних змінних:

Категориальні змінні перераховані в CATE_FEATURES

  • робочий клас
  • освіту
  • подружній
  • окупація
  • відносини
  • гонки
  • секс
  • Батьківщина

крім того, шість неперервних змінних:

Безперервні змінні перераховані в CONTI_FEATURES

  • вік
  • fnlwgt
  • номер_освіти
  • приріст капіталу
  • капітал_збиток
  • години_тиждень

Зауважте, що ми заповнюємо список вручну, щоб ви мали краще уявлення про те, які стовпці ми використовуємо. Швидший спосіб побудови категорійного або безперервного списку — це використання:

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

Ось код для імпорту даних:

# 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()
вік fnlwgt номер_освіти приріст капіталу капітал_збиток години_тиждень
вважати 32561.000000 3.256100e + 04 32561.000000 32561.000000 32561.000000 32561.000000
значити 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
хвилин 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
Макс 90.000000 1.484705e + 06 16.000000 99999.000000 4356.000000 99.000000

Ви можете перевірити кількість унікальних значень параметра native_country. Ви бачите, що лише одне домогосподарство походить з Голландії та Нідерландів. Це домогосподарство не надасть нам жодної інформації, але буде через помилку під час навчання.

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

Ви можете виключити цей неінформативний рядок із набору даних

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

Далі ви зберігаєте положення безперервних елементів у списку. Він знадобиться вам на наступному кроці для будівництва трубопроводу.

Наведений нижче код перегляне всі назви стовпців у CONTI_FEATURES і отримає їх розташування (тобто номер), а потім додасть його до списку під назвою 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]

Наведений нижче код виконує ту саму роботу, що й вище, але для категоріальної змінної. Код нижче повторює те, що ви робили раніше, за винятком категорійних функцій.

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

Ви можете переглянути набір даних. Зауважте, що кожна категорійна ознака є рядком. Ви не можете передати модель за допомогою рядкового значення. Вам потрібно перетворити набір даних за допомогою фіктивної змінної.

df_train.head(5)

Насправді вам потрібно створити один стовпець для кожної групи функції. По-перше, ви можете запустити наведений нижче код, щоб обчислити загальну кількість необхідних стовпців.

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

Весь набір даних містить 101 групу, як показано вище. Наприклад, особливості робочого класу мають дев'ять груп. Ви можете візуалізувати назви груп за допомогою наступних кодів

unique() повертає унікальні значення категорійних ознак.

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

Таким чином, навчальний набір даних міститиме 101 + 7 стовпців. Останні сім стовпців є безперервними функціями.

Scikit-learn може подбати про перетворення. Це робиться в два етапи:

  • Спочатку вам потрібно перетворити рядок на ID. Наприклад, State-gov матиме ID 1, Self-emp-not-inc ID 2 тощо. Функція LabelEncoder зробить це за вас
  • Перенесіть кожен ідентифікатор у новий стовпець. Як згадувалося раніше, набір даних має 101 ідентифікатор групи. Таким чином, буде 101 стовпець, що фіксуватиме всі групи категорійних ознак. Scikit-learn має функцію OneHotEncoder, яка виконує цю операцію

Крок 2) Створіть навчальний/тестовий набір

Тепер, коли набір даних готовий, ми можемо розділити його 80/20.

80 відсотків для навчального набору і 20 відсотків для тестового.

Ви можете використовувати train_test_split. Перший аргумент — фрейм даних — це функції, а другий аргумент — фрейм даних мітки. Ви можете вказати розмір набору тестів за допомогою 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)

Крок 3) Побудуйте трубопровід

Конвеєр полегшує заповнення моделі узгодженими даними.

Ідея полягає в тому, щоб помістити необроблені дані в «конвеєр» для виконання операцій.

Наприклад, з поточним набором даних вам потрібно стандартизувати безперервні змінні та перетворити категоричні дані. Зверніть увагу, що ви можете виконувати будь-яку операцію всередині конвеєра. Наприклад, якщо у вас є "NA" в наборі даних, ви можете замінити їх середнім або медіаною. Ви також можете створювати нові змінні.

У вас є вибір; жорстко закодуйте два процеси або створіть конвеєр. Перший вибір може призвести до витоку даних і створити невідповідності з часом. Кращим варіантом буде використання трубопроводу.

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

Трубопровід виконає дві операції перед подачею логістичного класифікатора:

  1. Стандартизуйте змінну: `StandardScaler()“
  2. Перетворення категоріальних ознак: OneHotEncoder(sparse=False)

Ви можете виконати два кроки за допомогою make_column_transformer. Ця функція недоступна в поточній версії scikit-learn (0.19). У поточній версії неможливо виконати кодер міток і один гарячий кодер у конвеєрі. Це одна з причин, чому ми вирішили використовувати версію для розробників.

make_column_transformer простий у використанні. Вам потрібно визначити, до яких стовпців застосовувати перетворення та яке перетворення виконувати. Наприклад, щоб стандартизувати безперервну функцію, ви можете:

  • conti_features, StandardScaler() всередині make_column_transformer.
    • conti_features: список із постійною змінною
    • StandardScaler: стандартизувати змінну

Об’єкт OneHotEncoder всередині make_column_transformer автоматично кодує мітку.

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

Ви можете перевірити, чи працює конвеєр, за допомогою fit_transform. Набір даних має мати таку форму: 26048, 107

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

Трансформатор даних готовий до використання. Ви можете створити конвеєр за допомогою make_pipeline. Після того, як дані будуть перетворені, ви можете виконати логістичну регресію.

model = make_pipeline(
    preprocess,
    LogisticRegression())

Навчання моделі за допомогою scikit-learn є тривіальним. Ви повинні використовувати об'єкт підгонки, якому передує конвеєр, тобто модель. Ви можете надрукувати точність за допомогою об’єкта оцінки з бібліотеки scikit-learn

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

Нарешті, ви можете передбачити класи за допомогою predict_proba. Він повертає ймовірність для кожного класу. Зверніть увагу, що це дорівнює одиниці.

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

Крок 4) Використання нашого конвеєра в пошуку сітки

Налаштування гіперпараметрів (змінних, які визначають структуру мережі, як приховані одиниці) може бути виснажливим і виснажливим.

Одним із способів оцінки моделі може бути зміна розміру навчального набору та оцінка ефективності.

Ви можете повторити цей метод десять разів, щоб побачити показники оцінки. Однак це занадто багато роботи.

Натомість scikit-learn надає функцію для налаштування параметрів і перехресної перевірки.

Перехресна перевірка

Перехресна перевірка означає, що під час навчання набір для навчання ковзає n разів у складках, а потім оцінює модель n разів. Наприклад, якщо cv встановлено на 10, навчальний набір навчається та оцінюється десять разів. У кожному раунді класифікатор випадковим чином обирає дев’ять складок для навчання моделі, а 10-й складок призначений для оцінки.

Пошук у сітці

Кожен класифікатор має гіперпараметри для налаштування. Ви можете спробувати різні значення або встановити сітку параметрів. Якщо ви зайдете на офіційний веб-сайт scikit-learn, ви побачите, що логістичний класифікатор має різні параметри для налаштування. Щоб зробити навчання швидшим, ви вирішуєте налаштувати параметр C. Він контролює параметр регулярізації. Воно повинно бути позитивним. Невелике значення надає регуляризатору більшої ваги.

Ви можете використовувати об'єкт GridSearchCV. Вам потрібно створити словник, що містить гіперпараметри для налаштування.

Ви перераховуєте гіперпараметри, а потім значення, які хочете спробувати. Наприклад, щоб налаштувати параметр C, ви використовуєте:

  • 'logisticregression__C': [0.1, 1.0, 1.0]: перед параметром стоїть назва класифікатора в нижньому регістрі та два символи підкреслення.

Модель спробує чотири різні значення: 0.001, 0.01, 0.1 і 1.

Ви тренуєте модель за допомогою 10 згорток: cv=10

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

Ви можете навчити модель за допомогою GridSearchCV з параметром gri та cv.

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

ВИХІД

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)

Щоб отримати доступ до найкращих параметрів, ви використовуєте best_params_

grid_clf.best_params_

ВИХІД

{'logisticregression__C': 1.0}

Після навчання моделі з чотирма різними значеннями регуляризації оптимальний параметр є

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

найкраща логістична регресія з пошуку по сітці: 0.850891

Щоб отримати доступ до прогнозованих ймовірностей:

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 із scikit-learn

Давайте спробуємо навчитися на прикладах Scikit-learn, щоб навчити один із найкращих класифікаторів на ринку. XGBoost є покращенням порівняно з випадковим лісом. Теоретичні основи класифікатора виходять за рамки цього Python Підручник Scikit. Майте на увазі, що XGBoost виграв багато змагань з каггла. З середнім розміром набору даних він може працювати так само добре, як алгоритм глибокого навчання або навіть краще.

Класифікатор є складним для навчання, оскільки він має велику кількість параметрів для налаштування. Ви, звичайно, можете використовувати GridSearchCV, щоб вибрати параметр для вас.

Натомість давайте подивимося, як використовувати кращий спосіб знайти оптимальні параметри. GridSearchCV може бути виснажливим і дуже довгим для навчання, якщо ви передаєте багато значень. Простір пошуку зростає разом із кількістю параметрів. Бажаним рішенням є використання RandomizedSearchCV. Цей метод полягає у випадковому виборі значень кожного гіперпараметра після кожної ітерації. Наприклад, якщо класифікатор навчається протягом 1000 ітерацій, тоді оцінюється 1000 комбінацій. Працює більш-менш так. GridSearchCV

Вам потрібно імпортувати xgboost. Якщо бібліотека не встановлена, скористайтеся pip3 install xgboost або

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

In Jupyter навколишнє середовище

Далі,

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

Наступний крок у цьому Scikit Python навчальний посібник включає вказівку параметрів для налаштування. Ви можете звернутися до офіційної документації, щоб побачити всі параметри для налаштування. Заради Python Підручник Sklearn, ви вибираєте лише два гіперпараметри з двома значеннями кожен. XGBoost потребує багато часу для навчання, чим більше гіперпараметрів у сітці, тим довше потрібно чекати.

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

Ви створюєте новий конвеєр за допомогою класифікатора XGBoost. Ви обираєте визначення 600 оцінювачів. Зауважте, що n_estimators – це параметр, який можна налаштувати. Високе значення може призвести до переобладнання. Ви можете самостійно спробувати різні значення, але майте на увазі, що це може зайняти години. Ви використовуєте значення за замовчуванням для інших параметрів

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

Ви можете покращити перехресну перевірку за допомогою перехресної перевірки Stratified K-Folds. Тут ви створюєте лише три складки, щоб пришвидшити обчислення, але знизити якість. Збільште це значення до 5 або 10 вдома, щоб покращити результати.

Ви обираєте навчання моделі протягом чотирьох ітерацій.

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)

Рандомізований пошук готовий до використання, ви можете навчити модель

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

Як бачите, XGBoost має кращий результат, ніж попередня регресія logisitc.

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)

Створіть DNN за допомогою MLPClassifier у scikit-learn

Нарешті, ви можете навчити алгоритм глибокого навчання за допомогою scikit-learn. Метод такий же, як і в іншого класифікатора. Класифікатор доступний на сайті MLPClassifier.

from sklearn.neural_network import MLPClassifier

Ви визначаєте наступний алгоритм глибокого навчання:

  • Адам розгадувач
  • Функція активації Relu
  • Альфа = 0.0001
  • розмір партії 150
  • Два прихованих шари з 100 і 50 нейронами відповідно
model_dnn = make_pipeline(
    preprocess,
    MLPClassifier(solver='adam',
                  alpha=0.0001,
                  activation='relu',
                    batch_size=150,
                    hidden_layer_sizes=(200, 100),
                    random_state=1))

Ви можете змінити кількість шарів, щоб покращити модель

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

Оцінка регресії DNN: 0.821253

LIME: довіряйте своїй моделі

Тепер, коли у вас є хороша модель, вам потрібен інструмент, щоб довіряти їй. навчання за допомогою машини Алгоритм, особливо випадковий ліс і нейронна мережа, як відомо, є алгоритмом чорної скриньки. Іншими словами, це працює, але ніхто не знає, чому.

Троє дослідників винайшли чудовий інструмент, щоб побачити, як комп’ютер робить прогноз. Стаття називається «Чому я повинен тобі довіряти?»

Вони розробили алгоритм під назвою Локальні інтерпретовані моделі-агностичні пояснення (LIME).

Візьмемо приклад:

іноді ви не знаєте, чи можна довіряти прогнозу машинного навчання:

Лікар, наприклад, не може довіряти діагнозу лише тому, що це сказав комп’ютер. Ви також повинні знати, чи можна довіряти моделі, перш ніж запускати її у виробництво.

Уявіть, що ми можемо зрозуміти, чому будь-який класифікатор робить прогнози навіть неймовірно складних моделей, таких як нейронні мережі, випадкові ліси або svms з будь-яким ядром

стане більш доступним для довіри прогнозу, якщо ми зможемо зрозуміти причини цього. З прикладу з лікарем, якби модель сказала йому, яким симптомам ви б довіряли, також легше зрозуміти, чи не варто довіряти моделі.

Лайм може розповісти, які особливості впливають на рішення класифікатора

Підготовка даних

Це кілька речей, які вам потрібно змінити, щоб запустити LIME пітон. Перш за все, потрібно встановити вапно в термінал. Ви можете використовувати піпсове вапно

Lime використовує об’єкт LimeTabularExplainer для наближення моделі локально. Цей об'єкт вимагає:

  • набір даних у форматі numpy
  • Назва об’єктів: назви_об’єктів
  • Ім'я класів: class_names
  • Індекс стовпця категорійних ознак: категоричні_ознаки
  • Назва групи для кожної категоріальної ознаки: categorical_names

Створіть набір поїздів numpy

Ви можете скопіювати та конвертувати df_train з pandas у нумпі дуже легко

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

Отримайте назву класу Мітка доступна за допомогою об’єкта unique(). Ви повинні побачити:

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

індекс колонки категоріальних ознак

Щоб отримати назву групи, ви можете використати метод, який ви використали раніше. Ви кодуєте мітку за допомогою LabelEncoder. Ви повторюєте операцію над усіма категоріальними ознаками.

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

Тепер, коли набір даних готовий, ви можете створити інший набір даних, як показано в прикладах навчання Scikit нижче. Ви фактично перетворюєте дані поза конвеєром, щоб уникнути помилок із LIME. Навчальний набір у LimeTabularExplainer має бути масивом numpy без рядка. За допомогою описаного вище методу у вас уже є перетворений навчальний набір даних.

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)

Ви можете зробити конвеєр з оптимальними параметрами з 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))])

Ви отримуєте попередження. Попередження пояснює, що вам не потрібно створювати кодувальник міток перед конвеєром. Якщо ви не хочете використовувати LIME, можете скористатися методом із першої частини підручника «Машинне навчання за допомогою Scikit-learn». В іншому випадку ви можете використовувати цей метод, спочатку створіть закодований набір даних, установіть отримання гарячого кодера в конвеєрі.

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)

Перш ніж використовувати LIME в дії, давайте створимо масив numpy з функціями неправильної класифікації. Ви можете використати цей список пізніше, щоб отримати уявлення про те, що ввело класифікатор в оману.

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)

Ви створюєте лямбда-функцію для отримання прогнозу з моделі з новими даними. Він вам незабаром знадобиться.

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

Ви перетворюєте фрейм даних pandas на масив 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)

Давайте виберемо випадкове домогосподарство з тестового набору та побачимо прогноз моделі та те, як комп’ютер зробив свій вибір.

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

Ви можете використовувати пояснювач з expand_instance, щоб перевірити пояснення моделі

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

Підготовка даних

Ми бачимо, що класифікатор правильно спрогнозував домогосподарство. Дохід справді вище 50 тис.

Перше, що ми можемо сказати, це те, що класифікатор не дуже впевнений щодо прогнозованих ймовірностей. Машина передбачає, що дохід домогосподарства перевищує 50 тисяч з імовірністю 64%. Ці 64% складаються з приросту капіталу та шлюбу. Синій колір негативно впливає на позитивний клас, а помаранчева лінія – позитивно.

Класифікатор заплутаний, оскільки приріст капіталу цієї домогосподарства дорівнює нулю, тоді як приріст капіталу зазвичай є хорошим показником багатства. Крім того, домогосподарство працює менше 40 годин на тиждень. Вік, професія та стать позитивно впливають на класифікатор.

Якби сімейний стан був неодруженим, класифікатор передбачив би дохід нижче 50 тис. (0.64-0.18 = 0.46)

Ми можемо спробувати з іншим домогосподарством, яке було неправильно класифіковано

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)

Підготовка даних

Класифікатор передбачив дохід нижче 50 тис. Поки це неправда. Цей будинок здається дивним. Він не має ні приросту капіталу, ні збитку капіталу. Він розлучений, йому 60 років, і це освічена людина, тобто, Education_num > 12. Відповідно до загальної моделі, це домогосподарство повинно, як пояснює класифікатор, отримувати дохід нижче 50 тис.

Ви намагаєтеся пограти з LIME. Ви помітите грубі помилки класифікатора.

Ви можете перевірити GitHub власника бібліотеки. Вони надають додаткову документацію для класифікації зображень і тексту.

Підсумки

Нижче наведено список деяких корисних команд із scikit learn версії >=0.20

створити набір даних навчання/тесту стажисти розділилися
Побудуйте трубопровід
виберіть стовпець і застосуйте перетворення makecolumntransformer
вид трансформації
стандартизувати StandardScaler
мін макс MinMaxScaler
Нормалізувати Нормалізатор
Введіть відсутнє значення приписувати
Перетворення категоричних OneHotEncoder
Припасуйте та трансформуйте дані fit_transform
Зробіть трубопровід make_pipeline
Базова модель
логістична регресія Логістична регресія
XGBoost XGBClassifier
Нейронна мережа MLPClassifier
Пошук у сітці GridSearchCV
Рандомізований пошук Рандомізований пошук CV