Учебное пособие по Scikit-Learn: установка и примеры Scikit-Learn
Что такое Scikit-learn?
Scikit учиться это открытый исходный код Python Библиотека для машинного обучения. Поддерживает самые современные алгоритмы, такие как KNN, XGBoost, случайный лес и SVM. Создана на основе NumPy. Scikit-learn широко используется в соревнованиях Kaggle, а также известными технологическими компаниями. Помогает в предварительной обработке, снижении размерности (выборе параметров), классификации, регрессии, кластеризации и выборе модели.
Scikit-learn имеет лучшую документацию среди всех библиотек с открытым исходным кодом. Он предоставляет вам интерактивную диаграмму на https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html.

Scikit-learn не очень сложен в использовании и дает отличные результаты. Однако scikit Learning не поддерживает параллельные вычисления. С его помощью можно запустить алгоритм глубокого обучения, но это не оптимальное решение, особенно если вы знаете, как использовать TensorFlow.
Как загрузить и установить Scikit-learn
Теперь в этом Python В учебнике Scikit-learn мы научимся загружать и устанавливать Scikit-learn:
Вариант 1: AWS
scikit-learn можно использовать поверх AWS. Пожалуйста относиться Образ Docker, в котором предустановлен scikit-learn.
Чтобы использовать версию для разработчиков, используйте команду в Jupyter
import sys !{sys.executable} -m pip install git+git://github.com/scikit-learn/scikit-learn.git
Вариант 2: Mac или Windows используя Анаконду
Чтобы узнать об установке Anaconda, см. https://www.guru99.com/download-install-tensorflow.html
Недавно разработчики scikit выпустили версию для разработки, которая решает распространенную проблему, с которой сталкивается текущая версия. Мы сочли более удобным использовать версию для разработчиков вместо текущей версии.
Как установить scikit-learn в среде Conda
Если вы установили scikit-learn в среде conda, выполните действия, необходимые для обновления до версии 0.20.
Шаг 1) Активировать среду тензорного потока
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 разделено на две части:
- Машинное обучение с scikit-learn
- Как доверить свою модель с LIME
В первой части подробно описано, как построить конвейер, создать модель и настроить гиперпараметры, а во второй части представлены самые современные методы выбора модели.
Шаг 1) Импортируйте данные
В этом учебном пособии по Scikit вы будете использовать набор данных для взрослых.
Дополнительную информацию об этом наборе данных см. Если вам интересно узнать больше об описательной статистике, воспользуйтесь инструментами «Погружение» и «Обзор».
Сослаться этот учебник узнать больше о погружении и обзоре
Вы импортируете набор данных с помощью Pandas. Обратите внимание, что вам необходимо преобразовать тип непрерывных переменных в формат с плавающей запятой.
Этот набор данных включает восемь категориальных переменных:
Категориальные переменные перечислены в CATE_FEATURES.
- рабочий класс
- образование
- брачный
- оккупация
- отношения
- раса
- секс
- родная страна
причем шесть непрерывных переменных:
Непрерывные переменные перечислены в CONTI_FEATURES.
- возраст
- фнлвгт
- образование_номер
- прирост капитала
- капитал_убыток
- часы_неделя
Обратите внимание, что мы заполняем список вручную, чтобы вы имели лучшее представление о том, какие столбцы мы используем. Более быстрый способ создания категориального или непрерывного списка — использовать:
## 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()
возраст | фнлвгт | образование_номер | прирост капитала | капитал_убыток | часы_неделя | |
---|---|---|---|---|---|---|
считать | 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 |
станд | 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 может позаботиться о преобразовании. Это делается в два этапа:
- Сначала вам нужно преобразовать строку в идентификатор. Например, State-gov будет иметь идентификатор 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
Перед подачей в логистический классификатор конвейер выполнит две операции:
- Стандартизируйте переменную: «StandardScaler()».
- Преобразуйте категориальные функции: 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, вы используете:
- «логистическая регрессия__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 выиграл множество соревнований по Kaggle. При среднем размере набора данных он может работать так же хорошо, как алгоритм глубокого обучения, или даже лучше.
Классификатор сложно обучать, поскольку он требует настройки большого количества параметров. Вы, конечно, можете использовать 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 имеет лучший результат, чем предыдущая логистическая регрессия.
print("лучших parameter", random_search.best_params_) print("best logistic regression from grid search: %f" % random_search.best_estimator_.score(X_test, y_test))
лучших 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).
Вот пример:
иногда вы не знаете, можно ли доверять прогнозу машинного обучения:
Врач, например, не может доверять диагнозу только потому, что так сказал компьютер. Вам также необходимо знать, можно ли доверять модели, прежде чем запускать ее в производство.
Представьте, что мы можем понять, почему любой классификатор делает прогноз, даже невероятно сложные модели, такие как нейронные сети, случайные леса или SVM с любым ядром.
станет более доступным для доверия предсказанию, если мы сможем понять причины, лежащие в его основе. Из примера с врачом, если модель сказала ему, какие симптомы являются существенными, вы бы ей доверяли, также легче понять, не следует ли вам доверять модели.
Лайм может подсказать, какие особенности влияют на решения классификатора.
Подготовка данных
Это пара вещей, которые вам нужно изменить, чтобы запустить LIME. питон. Прежде всего, вам необходимо установить в терминал лайм. Вы можете использовать pip install лайм
Lime использует объект LimeTabularExplainer для локальной аппроксимации модели. Этот объект требует:
- набор данных в формате numpy
- Название функций: Feature_names
- Название классов: class_names
- Индекс столбца категориальных признаков: categorical_features
- Имя группы для каждого категориального признака: categorical_names.
Создать набор поездов numpy
Вы можете скопировать и преобразовать df_train из панд в NumPy очень легко
df_train.head(5) # Create numpy data df_lime = df_train df_lime.head(3)
Получить имя класса Метка доступна с помощью объекта unique(). Тебе следует увидеть:
- '<= 50 КБ'
- '> 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 должен представлять собой пустой массив без строки. Используя описанный выше метод, у вас уже есть преобразованный набор обучающих данных.
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])
Вы можете использовать объяснитель с объяснением_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.
создать набор данных для поездов/тестов | Стажеры разделились |
Построить трубопровод | |
выберите столбец и примените преобразование | сделатьколонкутрансформатор |
тип трансформации | |
стандартизировать | StandardScaler |
мин Макс | MinMaxScaler |
нормировать | нормализ |
Вменить недостающее значение | вменять |
Преобразование категориального | OneHotEncoder |
Сопоставьте и преобразуйте данные | fit_transform |
Сделать трубопровод | make_pipeline |
Базовая модель | |
логистическая регрессия | Логистическая регрессия |
XGBoost | XGBКлассификатор |
Нейронная сеть | MLPКлассификатор |
Поиск по сетке | GridSearchCV |
Рандомизированный поиск | Рандомизированный поискрезюме |