Contents
Что такое 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 не очень сложен в использовании и дает отличные результаты. Однако scikitlearn не поддерживает параллельные вычисления. С ним можно запустить алгоритм глубокого обучения, но это не оптимальное решение, особенно если вы знаете, как использовать TensorFlow.
Как скачать и установить Scikit-learn
Теперь в этом руководстве по Python Scikit-learn мы узнаем, как загрузить и установить Scikit-learn:
Вариант 1: АМС
scikit-learn можно использовать через AWS. Пожалуйста , обратитесь к образу докера с предустановленным scikit-learn.
Чтобы использовать версию для разработчиков, используйте команду в 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
Если вы установили 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 Visual C++ 14. Вы можете скачать его здесь .
Пример Scikit-Learn с машинным обучением
Этот учебник Scikit разделен на две части:
- Машинное обучение с scikit-learn
- Как доверить свою модель с помощью LIME
В первой части подробно рассказывается, как построить конвейер, создать модель и настроить гиперпараметры, а во второй части представлены самые современные сведения о выборе модели.
Шаг 1) Импорт данных
В этом учебном пособии по Scikit вы будете использовать набор данных для взрослых.
Для получения дополнительной информации об этом наборе данных см. Если вам интересно узнать больше об описательной статистике, используйте инструменты «Погружение» и «Обзор».
Обратитесь к этому руководству, чтобы узнать больше о погружении и обзоре.
Вы импортируете набор данных с помощью Pandas. Обратите внимание, что вам необходимо преобразовать тип непрерывных переменных в формат с плавающей запятой.
Обратите внимание, что мы заполняем список вручную, чтобы вы лучше понимали, какие столбцы мы используем. Более быстрый способ построить список категориальных или непрерывных состоит в том, чтобы использовать:
## 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')
возраст | фнлвгт | Education_num | прирост капитала | капитал_убыток | часы_неделя | |
---|---|---|---|---|---|---|
считать | 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
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 группу, как показано выше. Например, характеристики рабочего класса имеют девять групп. Вы можете визуализировать название групп со следующими кодами
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']
unique() возвращает уникальные значения категориальных признаков.
Следовательно, обучающий набор данных будет содержать 101 + 7 столбцов. Последние семь столбцов — это непрерывные функции.
Scikit-learn может позаботиться о преобразовании. Делается в два этапа:
- Во-первых, вам нужно преобразовать строку в идентификатор. Например, State-gov будет иметь идентификатор 1, идентификатор Self-emp-not-inc 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 тривиально. Вам нужно использовать подгонку объекта, которому предшествует конвейер, т.е. модель. Вы можете распечатать точность с помощью объекта score из библиотеки 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 выиграл множество соревнований kaggle. При среднем размере набора данных он может работать так же хорошо, как алгоритм глубокого обучения, или даже лучше.
Классификатор сложно обучать, потому что он имеет большое количество параметров для настройки. Вы можете, конечно, использовать GridSearchCV, чтобы выбрать параметр для вас.
Вместо этого давайте посмотрим, как лучше найти оптимальные параметры. GridSearchCV может быть утомительным и очень долгим для обучения, если вы передаете много значений. Пространство поиска растет вместе с количеством параметров. Предпочтительным решением является использование RandomizedSearchCV. Этот метод состоит в случайном выборе значений каждого гиперпараметра после каждой итерации. Например, если классификатор обучен за 1000 итераций, то оценивается 1000 комбинаций. Работает более-менее вроде. GridSearchCV
Вам нужно импортировать xgboost. Если библиотека не установлена, используйте pip3 install xgboost или
use import sys !{sys.executable} -m pip install xgboost
В среде Юпитера
Следующий,
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("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))
LIME: доверяйте своей модели
Теперь, когда у вас есть хорошая модель, вам нужен инструмент, чтобы доверять ей. Алгоритм машинного обучения , особенно случайный лес и нейронная сеть, известен как алгоритм черного ящика. Скажем иначе, это работает, но никто не знает, почему.
Три исследователя придумали отличный инструмент, чтобы увидеть, как компьютер делает прогноз. Статья называется «Почему я должен вам доверять?».
Они разработали алгоритм под названием Local Interpretable Model-Agnostic Explanations (LIME) .
Возьмите пример:
иногда вы не знаете, можно ли доверять прогнозу машинного обучения:
Врач, например, не может доверять диагнозу только потому, что так сказал компьютер. Вы также должны знать, можете ли вы доверять модели, прежде чем запускать ее в производство.
Представьте, что мы можем понять, почему любой классификатор делает прогноз даже невероятно сложных моделей, таких как нейронные сети, случайные леса или svms с любым ядром.
станет более доступным для доверия прогнозу, если мы сможем понять причины, стоящие за ним. Из примера с врачом, если бы модель сказала ему, какие симптомы существенны, вы бы ей доверились, также легче понять, не стоит ли вам доверять модели.
Lime может подсказать, какие функции влияют на решения классификатора.
Подготовка данных
Это пара вещей, которые вам нужно изменить, чтобы запустить LIME с python . В первую очередь нужно установить лайм в терминал. Вы можете использовать pip install лайм
Lime использует объект LimeTabularExplainer для локальной аппроксимации модели. Этот объект требует:
- набор данных в формате numpy
- Название функций: feature_names
- Название классов: class_names
- Индекс столбца категориальных признаков: categorical_features
- Имя группы для каждой категориальной функции: categorical_names
Создать набор поездов numpy
Вы можете очень легко скопировать и преобразовать df_train из pandas в numpy.
df_train.head(5) # Create numpy data df_lime = df_train df_lime.head(3)
Получить имя класса Метка доступна с помощью объекта unique(). Тебе следует увидеть:
- ‘<=50K’
- ‘> 50 тыс.’
# 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]) Вы можете использовать объяснитель с объяснением_экземпляра, чтобы проверить объяснение модели.
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.
создать набор данных поезда/теста | трейни разделились |
Построить трубопровод | |
выберите столбец и примените преобразование | сделатьколоннтрансформер |
тип преобразования | |
стандартизировать | Стандартный масштабатор |
мин Макс | МинМаксСкалер |
нормализовать | нормализатор |
Вменить отсутствующее значение | Импутер |
Преобразовать категориальный | OneHotEncoder |
Подгонка и преобразование данных | fit_transform |
Сделать конвейер | make_pipeline |
Базовая модель | |
логистическая регрессия | Логистическая регрессия |
XGBoost | XGBКлассификатор |
Нейронная сеть | MLPКлассификатор |
Поиск по сетке | GridSearchCV |
Рандомизированный поиск | Рандомизированный поискрезюме |
Статья является переводом guru99-com