Что выдает предикт в машинном обучении питон
Перейти к содержимому

Что выдает предикт в машинном обучении питон

Метрики в задачах машинного обучения

В задачах машинного обучения для оценки качества моделей и сравнения различных алгоритмов используются метрики, а их выбор и анализ — непременная часть работы датасатаниста.

В этой статье мы рассмотрим некоторые критерии качества в задачах классификации, обсудим, что является важным при выборе метрики и что может пойти не так.

Метрики в задачах классификации

Для демонстрации полезных функций sklearn и наглядного представления метрик мы будем использовать датасет по оттоку клиентов телеком-оператора.

Загрузим необходимые библиотеки и посмотрим на данные

import pandas as pd import matplotlib.pyplot as plt from matplotlib.pylab import rc, plot import seaborn as sns from sklearn.preprocessing import LabelEncoder, OneHotEncoder from sklearn.model_selection import cross_val_score from sklearn.linear_model import LogisticRegression from sklearn.ensemble import RandomForestClassifier, GradientBoostingClassifier from sklearn.metrics import precision_recall_curve, classification_report from sklearn.model_selection import train_test_split df = pd.read_csv('../../data/telecom_churn.csv') 
df.head(5)

Предобработка данных

# Сделаем маппинг бинарных колонок # и закодируем dummy-кодированием штат (для простоты, лучше не делать так для деревянных моделей) d = df['International plan'] = df['International plan'].map(d) df['Voice mail plan'] = df['Voice mail plan'].map(d) df['Churn'] = df['Churn'].astype('int64') le = LabelEncoder() df['State'] = le.fit_transform(df['State']) ohe = OneHotEncoder(sparse=False) encoded_state = ohe.fit_transform(df['State'].values.reshape(-1, 1)) tmp = pd.DataFrame(encoded_state, columns=['state ' + str(i) for i in range(encoded_state.shape[1])]) df = pd.concat([df, tmp], axis=1)

Accuracy, precision и recall

Перед переходом к самим метрикам необходимо ввести важную концепцию для описания этих метрик в терминах ошибок классификации — confusion matrix (матрица ошибок).
Допустим, что у нас есть два класса и алгоритм, предсказывающий принадлежность каждого объекта одному из классов, тогда матрица ошибок классификации будет выглядеть следующим образом:

True Positive (TP) False Positive (FP)
False Negative (FN) True Negative (TN)

Здесь — это ответ алгоритма на объекте, а — истинная метка класса на этом объекте.
Таким образом, ошибки классификации бывают двух видов: False Negative (FN) и False Positive (FP).

Обучение алгоритма и построение матрицы ошибок

X = df.drop('Churn', axis=1) y = df['Churn'] # Делим выборку на train и test, все метрики будем оценивать на тестовом датасете X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, test_size=0.33, random_state=42) # Обучаем ставшую родной логистическую регрессию lr = LogisticRegression(random_state=42) lr.fit(X_train, y_train) # Воспользуемся функцией построения матрицы ошибок из документации sklearn def plot_confusion_matrix(cm, classes, normalize=False, title='Confusion matrix', cmap=plt.cm.Blues): """ This function prints and plots the confusion matrix. Normalization can be applied by setting `normalize=True`. """ plt.imshow(cm, interpolation='nearest', cmap=cmap) plt.title(title) plt.colorbar() tick_marks = np.arange(len(classes)) plt.xticks(tick_marks, classes, rotation=45) plt.yticks(tick_marks, classes) if normalize: cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis] print("Normalized confusion matrix") else: print('Confusion matrix, without normalization') print(cm) thresh = cm.max() / 2. for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): plt.text(j, i, cm[i, j], horizontalalignment="center", color="white" if cm[i, j] > thresh else "black") plt.tight_layout() plt.ylabel('True label') plt.xlabel('Predicted label') font = plt.rc('font', **font) cnf_matrix = confusion_matrix(y_test, lr.predict(X_test)) plt.figure(figsize=(10, 8)) plot_confusion_matrix(cnf_matrix, classes=['Non-churned', 'Churned'], title='Confusion matrix') plt.savefig("conf_matrix.png") plt.show() 

Accuracy

Интуитивно понятной, очевидной и почти неиспользуемой метрикой является accuracy — доля правильных ответов алгоритма:

Эта метрика бесполезна в задачах с неравными классами, и это легко показать на примере.

Допустим, мы хотим оценить работу спам-фильтра почты. У нас есть 100 не-спам писем, 90 из которых наш классификатор определил верно (True Negative = 90, False Positive = 10), и 10 спам-писем, 5 из которых классификатор также определил верно (True Positive = 5, False Negative = 5).
Тогда accuracy:

Однако если мы просто будем предсказывать все письма как не-спам, то получим более высокую accuracy:

При этом, наша модель совершенно не обладает никакой предсказательной силой, так как изначально мы хотели определять письма со спамом. Преодолеть это нам поможет переход с общей для всех классов метрики к отдельным показателям качества классов.

Precision, recall и F-мера

Для оценки качества работы алгоритма на каждом из классов по отдельности введем метрики precision (точность) и recall (полнота).

Precision можно интерпретировать как долю объектов, названных классификатором положительными и при этом действительно являющимися положительными, а recall показывает, какую долю объектов положительного класса из всех объектов положительного класса нашел алгоритм.

Именно введение precision не позволяет нам записывать все объекты в один класс, так как в этом случае мы получаем рост уровня False Positive. Recall демонстрирует способность алгоритма обнаруживать данный класс вообще, а precision — способность отличать этот класс от других классов.

Как мы отмечали ранее, ошибки классификации бывают двух видов: False Positive и False Negative. В статистике первый вид ошибок называют ошибкой I-го рода, а второй — ошибкой II-го рода. В нашей задаче по определению оттока абонентов, ошибкой первого рода будет принятие лояльного абонента за уходящего, так как наша нулевая гипотеза состоит в том, что никто из абонентов не уходит, а мы эту гипотезу отвергаем. Соответственно, ошибкой второго рода будет являться «пропуск» уходящего абонента и ошибочное принятие нулевой гипотезы.

Precision и recall не зависят, в отличие от accuracy, от соотношения классов и потому применимы в условиях несбалансированных выборок.
Часто в реальной практике стоит задача найти оптимальный (для заказчика) баланс между этими двумя метриками. Классическим примером является задача определения оттока клиентов.
Очевидно, что мы не можем находить всех уходящих в отток клиентов и только их. Но, определив стратегию и ресурс для удержания клиентов, мы можем подобрать нужные пороги по precision и recall. Например, можно сосредоточиться на удержании только высокодоходных клиентов или тех, кто уйдет с большей вероятностью, так как мы ограничены в ресурсах колл-центра.

Обычно при оптимизации гиперпараметров алгоритма (например, в случае перебора по сетке GridSearchCV ) используется одна метрика, улучшение которой мы и ожидаем увидеть на тестовой выборке.
Существует несколько различных способов объединить precision и recall в агрегированный критерий качества. F-мера (в общем случае ) — среднее гармоническое precision и recall :

в данном случае определяет вес точности в метрике, и при это среднее гармоническое (с множителем 2, чтобы в случае precision = 1 и recall = 1 иметь )
F-мера достигает максимума при полноте и точности, равными единице, и близка к нулю, если один из аргументов близок к нулю.
В sklearn есть удобная функция _metrics.classificationreport, возвращающая recall, precision и F-меру для каждого из классов, а также количество экземпляров каждого класса.

report = classification_report(y_test, lr.predict(X_test), target_names=['Non-churned', 'Churned']) print(report) 
class precision recall f1-score support
Non-churned 0.88 0.97 0.93 941
Churned 0.60 0.25 0.35 159
avg / total 0.84 0.87 0.84 1100

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

AUC-ROC и AUC-PR

При конвертации вещественного ответа алгоритма (как правило, вероятности принадлежности к классу, отдельно см. SVM) в бинарную метку, мы должны выбрать какой-либо порог, при котором 0 становится 1. Естественным и близким кажется порог, равный 0.5, но он не всегда оказывается оптимальным, например, при вышеупомянутом отсутствии баланса классов.

Одним из способов оценить модель в целом, не привязываясь к конкретному порогу, является AUC-ROC (или ROC AUC) — площадь (Area Under Curve) под кривой ошибок (Receiver Operating Characteristic curve ). Данная кривая представляет из себя линию от (0,0) до (1,1) в координатах True Positive Rate (TPR) и False Positive Rate (FPR):

TPR нам уже известна, это полнота, а FPR показывает, какую долю из объектов negative класса алгоритм предсказал неверно. В идеальном случае, когда классификатор не делает ошибок (FPR = 0, TPR = 1) мы получим площадь под кривой, равную единице; в противном случае, когда классификатор случайно выдает вероятности классов, AUC-ROC будет стремиться к 0.5, так как классификатор будет выдавать одинаковое количество TP и FP.
Каждая точка на графике соответствует выбору некоторого порога. Площадь под кривой в данном случае показывает качество алгоритма (больше — лучше), кроме этого, важной является крутизна самой кривой — мы хотим максимизировать TPR, минимизируя FPR, а значит, наша кривая в идеале должна стремиться к точке (0,1).

Код отрисовки ROC-кривой

sns.set(font_scale=1.5) sns.set_color_codes("muted") plt.figure(figsize=(10, 8)) fpr, tpr, thresholds = roc_curve(y_test, lr.predict_proba(X_test)[:,1], pos_label=1) lw = 2 plt.plot(fpr, tpr, lw=lw, label='ROC curve ') plt.plot([0, 1], [0, 1]) plt.xlim([0.0, 1.0]) plt.ylim([0.0, 1.05]) plt.xlabel('False Positive Rate') plt.ylabel('True Positive Rate') plt.title('ROC curve') plt.savefig("ROC.png") plt.show() 

Критерий AUC-ROC устойчив к несбалансированным классам (спойлер: увы, не всё так однозначно) и может быть интерпретирован как вероятность того, что случайно выбранный positive объект будет проранжирован классификатором выше (будет иметь более высокую вероятность быть positive), чем случайно выбранный negative объект.

Рассмотрим следующую задачу: нам необходимо выбрать 100 релевантных документов из 1 миллиона документов. Мы намашинлернили два алгоритма:

  • Алгоритм 1 возвращает 100 документов, 90 из которых релевантны. Таким образом,
  • Алгоритм 2 возвращает 2000 документов, 90 из которых релевантны. Таким образом,

Скорее всего, мы бы выбрали первый алгоритм, который выдает очень мало False Positive на фоне своего конкурента. Но разница в False Positive Rate между этими двумя алгоритмами крайне мала — всего 0.0019. Это является следствием того, что AUC-ROC измеряет долю False Positive относительно True Negative и в задачах, где нам не так важен второй (больший) класс, может давать не совсем адекватную картину при сравнении алгоритмов.

Для того чтобы поправить положение, вернемся к полноте и точности :

Здесь уже заметна существенная разница между двумя алгоритмами — 0.855 в точности!

Precision и recall также используют для построения кривой и, аналогично AUC-ROC, находят площадь под ней.

Здесь можно отметить, что на маленьких датасетах площадь под PR-кривой может быть чересчур оптимистична, потому как вычисляется по методу трапеций, но обычно в таких задачах данных достаточно. За подробностями о взаимоотношениях AUC-ROC и AUC-PR можно обратиться сюда.

Logistic Loss

Особняком стоит логистическая функция потерь, определяемая как:

здесь — это ответ алгоритма на -ом объекте, — истинная метка класса на -ом объекте, а размер выборки.

Подробно про математическую интерпретацию логистической функции потерь уже написано в рамках поста про линейные модели.
Данная метрика нечасто выступает в бизнес-требованиях, но часто — в задачах на kaggle.
Интуитивно можно представить минимизацию logloss как задачу максимизации accuracy путем штрафа за неверные предсказания. Однако необходимо отметить, что logloss крайне сильно штрафует за уверенность классификатора в неверном ответе.

def logloss_crutch(y_true, y_pred, eps=1e-15): return - (y_true * np.log(y_pred) + (1 - y_true) * np.log(1 - y_pred)) print('Logloss при неуверенной классификации %f' % logloss_crutch(1, 0.5)) >> Logloss при неуверенной классификации 0.693147 print('Logloss при уверенной классификации и верном ответе %f' % logloss_crutch(1, 0.9)) >> Logloss при уверенной классификации и верном ответе 0.105361 print('Logloss при уверенной классификации и НЕверном ответе %f' % logloss_crutch(1, 0.1)) >> Logloss при уверенной классификации и НЕверном ответе 2.302585

Отметим, как драматически выросла logloss при неверном ответе и уверенной классификации!
Следовательно, ошибка на одном объекте может дать существенное ухудшение общей ошибки на выборке. Такие объекты часто бывают выбросами, которые нужно не забывать фильтровать или рассматривать отдельно.
Всё становится на свои места, если нарисовать график logloss:

Видно, что чем ближе к нулю ответ алгоритма при ground truth = 1, тем выше значение ошибки и круче растёт кривая.

Подытожим:

  • В случае многоклассовой классификации нужно внимательно следить за метриками каждого из классов и следовать логике решения задачи, а не оптимизации метрики
  • В случае неравных классов нужно подбирать баланс классов для обучения и метрику, которая будет корректно отражать качество классификации
  • Выбор метрики нужно делать с фокусом на предметную область, предварительно обрабатывая данные и, возможно, сегментируя (как в случае с делением на богатых и бедных клиентов)

Полезные ссылки

  1. Курс Евгения Соколова: Семинар по выбору моделей (там есть информация по метрикам задач регрессии)
  2. Задачки на AUC-ROC от А.Г. Дьяконова
  3. Дополнительно о других метриках можно почитать на kaggle. К описанию каждой метрики добавлена ссылка на соревнования, где она использовалась
  4. Презентация Богдана Мельника aka ld86 про обучение на несбалансированных выборках

Благодарности

Спасибо mephistopheies и madrugado за помощь в подготовке статьи.

Делаем проект по машинному обучению на Python. Часть 2

Собрать воедино все части проекта по машинному обучению бывает весьма непросто. В этой серии статей мы пройдём через все этапы реализации процесса машинного обучения с использованием реальных данных, и узнаем, как сочетаются друг с другом различные методики.

В первой статье мы очистили и структурировали данные, провели разведочный анализ, собрали набор признаков для использования в модели и установили базовый уровень для оценки результатов. С помощью этой статьи мы научимся реализовывать на Python и сравнивать несколько моделей машинного обучения, проводить гиперпараметрическую настройку для оптимизации лучшей модели, и оценивать работу финальной модели на тестовом наборе данных.

Весь код проекта лежит на GitHub, а здесь находится второй блокнот, относящийся к текущей статье. Можете использовать и модифицировать код по своему усмотрению!

Оценка и выбор модели

Памятка: мы работаем над задачей с контролируемой регрессией, используем информацию об энергопотреблении зданий в Нью-Йорке для создания модели, которая прогнозировала бы, какой балл Energy Star Score получит то или иное здание. Нас интересует как точность прогнозирования, так и интерпретируемость модели.

Сегодня вы можете выбирать из множества доступных моделей машинного обучения, и это изобилие бывает пугающим. Конечно, в сети есть сравнительные обзоры, которые помогут сориентироваться при выборе алгоритма, но я предпочитаю попробовать в работе несколько и посмотреть, какой лучше. Машинное обучение по большей части основывается на эмпирических, а не теоретических результатах, и практически невозможно заранее понять, какая модель окажется точнее.

Обычно рекомендуется начинать с простых, интерпретируемых моделей, таких как линейная регрессия, и если результаты будут неудовлетворительными, то переходить к более сложным, но обычно более точным методам. На этом графике (весьма антинаучном) показана взаимосвязь точности и интерпретируемости некоторых алгоритмов:

Интерпретируемость и точность (Источник).

Мы будем оценивать пять моделей разной степени сложности:

  • Линейная регрессия.
  • Метод k-ближайших соседей.
  • «Случайный лес».
  • Градиентный бустинг.
  • Метод опорных векторов.
Заполняем отсутствующие значения

Хотя при очистке данных мы отбросили колонки, в которых не хватает больше половины значений, у нас ещё отсутствует немало значений. Модели машинного обучения не могут работать с отсутствующими данными, поэтому нам нужно их заполнить.

Сначала считаем данные и вспоминаем, как они выглядят:

import pandas as pd import numpy as np # Read in data into dataframes train_features = pd.read_csv('data/training_features.csv') test_features = pd.read_csv('data/testing_features.csv') train_labels = pd.read_csv('data/training_labels.csv') test_labels = pd.read_csv('data/testing_labels.csv') Training Feature Size: (6622, 64) Testing Feature Size: (2839, 64) Training Labels Size: (6622, 1) Testing Labels Size: (2839, 1)

Каждое NaN -значение — это отсутствующая запись в данных. Заполнять их можно по-разному, а мы воспользуемся достаточно простым методом медианного заполнения (median imputation), который заменяет отсутствующие данные средним значениями по соответствующим колонкам.

В нижеприведённом коде мы создадим Scikit-Learn-объект Imputer с медианной стратегией. Затем обучим его на обучающих данных (с помощью imputer.fit ), и применим для заполнения отсутствующих значений в обучающем и тестовом наборах (с помощью imputer.transform ). То есть записи, которых не хватает в тестовых данных, будут заполняться соответствующим медианным значением из обучающих данных.

Мы делаем заполнение и не обучаем модель на данных как есть, чтобы избежать проблемы с утечкой тестовых данных, когда информация из тестового датасета переходит в обучающий.

# Create an imputer object with a median filling strategy imputer = Imputer(strategy='median') # Train on the training features imputer.fit(train_features) # Transform both training data and testing data X = imputer.transform(train_features) X_test = imputer.transform(test_features) Missing values in training features: 0 Missing values in testing features: 0

Теперь все значения заполнены, пропусков нет.

Масштабирование признаков

Масштабированием называется общий процесс изменения диапазона признака. Это необходимый шаг, потому что признаки измеряются в разных единицах, а значит покрывают разные диапазоны. Это сильно искажает результаты таких алгоритмов, как метод опорных векторов и метод k-ближайших соседей, которые учитывают расстояния между измерениями. А масштабирование позволяет этого избежать. И хотя методы вроде линейной регрессии и «случайного леса» не требует масштабирования признаков, лучше не пренебрегать этим этапом при сравнении нескольких алгоритмов.

Масштабировать будем с помощью приведения каждого признака к диапазону от 0 до 1. Берём все значения признака, выбираем минимальное и делим его на разницу между максимальным и минимальным (диапазон). Такой способ масштабирования часто называют нормализацией, а другой основной способ — стандартизацией.

Этот процесс легко реализовать вручную, поэтому воспользуемся объектом MinMaxScaler из Scikit-Learn. Код для этого метода идентичен коду для заполнения отсутствующих значений, только вместо вставки применяется масштабирование. Напомним, что учим модель только на обучающем наборе, а затем преобразуем все данные.

# Create the scaler object with a range of 0-1 scaler = MinMaxScaler(feature_range=(0, 1)) # Fit on the training data scaler.fit(X) # Transform both the training and testing data X = scaler.transform(X) X_test = scaler.transform(X_test)

Теперь у каждого признака минимальное значение равно 0, а максимальное 1. Заполнение отсутствующих значений и масштабирование признаков — эти два этапа нужны почти в любом процессе машинного обучения.

Реализуем в Scikit-Learn модели машинного обучения

После всех подготовительных работ процесс создания, обучения и прогона моделей относительно прост. Мы будем использовать в Python библиотеку Scikit-Learn, прекрасно документированную и с продуманным синтаксисом построения моделей. Научившись создавать модель в Scikit-Learn, вы сможете быстро реализовывать всевозможные алгоритмы.

Иллюстрировать процесс создания, обучения ( .fit ) и тестирования ( .predict ) мы будем с помощью градиентного бустинга:

from sklearn.ensemble import GradientBoostingRegressor # Create the model gradient_boosted = GradientBoostingRegressor() # Fit the model on the training data gradient_boosted.fit(X, y) # Make predictions on the test data predictions = gradient_boosted.predict(X_test) # Evaluate the model mae = np.mean(abs(predictions - y_test)) print('Gradient Boosted Performance on the test set: MAE = %0.4f' % mae) Gradient Boosted Performance on the test set: MAE = 10.0132

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

Чтобы объективно оценивать модели, мы с помощью медианного значения цели вычислили базовый уровень и получили 24,5. А полученные результаты оказались значительно лучше, так что нашу задачу можно решить с помощью машинного обучения.

В нашем случае градиентный бустинг (MAE = 10,013) оказался чуть лучше «случайного леса» (10,014 MAE). Хотя эти результаты нельзя считать абсолютно честными, потому что для гиперпараметров мы по большей части используем значения по умолчанию. Эффективность моделей сильно зависит от этих настроек, особенно в методе опорных векторов. Тем не менее на основании этих результатов мы выберем градиентный бустинг и станем его оптимизировать.

Гиперпараметрическая оптимизация модели

После выбора модели можно оптимизировать её под решаемую задачу, настраивая гиперпараметры.

  • Гиперпараметры модели можно считать настройками алгоритма, которые мы задаём до начала его обучения. Например, гиперпараметром является количество деревьев в «случайном лесе», или количество соседей в методе k-ближайших соседей.
  • Параметры модели — то, что она узнаёт в ходе обучения, например, веса в линейной регрессии.

Переобучением называется ситуация, когда модель по сути запоминает учебные данные. У переобученной модели высокая дисперсия (variance), которую можно скорректировать с помощью ограничения сложности модели посредством регуляризации. Как недообученная, так и переобученная модель не сможет хорошо обобщить тестовые данные.

Трудность выбора правильных гиперпараметров заключается в том, что для каждой задачи будет уникальный оптимальный набор. Поэтому единственный способ выбрать наилучшие настройки — попробовать разные комбинации на новом датасете. К счастью, в Scikit-Learn есть ряд методов, позволяющих эффективно оценивать гиперпараметры. Более того, в проектах вроде TPOT делаются попытки оптимизировать поиск гиперпараметров с помощью таких подходов, как генетическое программирование. В этой статье мы ограничимся использованием Scikit-Learn.

Случайный поиск с перекрёстной проверкой

Давайте реализуем метод настройки гиперпараметров, который называется случайным поискок с перекрёстной проверкой:

  • Случайный поиск — методика выбора гиперпараметров. Мы определяем сетку, а потом из неё случайно выбираем различные комбинации, в отличие от сеточного поиска (grid search), при котором мы последовательно пробуем каждую комбинацию. Кстати, случайный поиск работает почти так же хорошо, как и сеточный, но гораздо быстрее.
  • Перекрёстной проверкой называется способ оценки выбранной комбинации гиперпараметров. Вместо разделения данных на обучающий и тестовый наборы, что уменьшает количество доступных для обучения данных, мы воспользуемся k-блочной перекрёстной проверкой (K-Fold Cross Validation). Для этого мы разделим обучающие данные на k блоков, а затем прогоним итеративный процесс, в ходе которого сначала обучим модель на k-1 блоках, а затем сравним результат при обучении на k-ом блоке. Будем повторять процесс k раз, и в конце получим среднее значение ошибки для каждой итерации. Это и будет финальная оценка.

Весь процесс случайного поиска с перекрёстной проверкой выглядит так:

  1. Задаём сетку гиперпараметров.
  2. Случайно выбираем комбинацию гиперпараметров.
  3. Создаём модель с использованием этой комбинации.
  4. Оцениваем результат работы модели с помощью k-блочной перекрёстной проверки.
  5. Решаем, какие гиперпараметры дают лучший результат.
Небольшое отступление: Методы градиентного бустинга

Мы будем использовать регрессионную модель на основе градиентного бустинга. Это сборный метод, то есть модель состоит из многочисленных «слабых учеников» (weak learners), в данном случае из отдельных деревьев решений (decision trees). Если в пакетных алгоритмах вроде «случайного леса» ученики обучаются параллельно, а затем методом голосования выбирается результат прогнозирования, то в boosting-алгоритмах вроде градиентного бустинга ученики обучаются последовательно, и каждый из них «сосредотачивается» на ошибках, сделанных предшественниками.

В последние годы boosting-алгоритмы стали популярны и часто побеждают на соревнованиях по машинному обучению. Градиентный бустинг — одна из реализаций, в которой для минимизации стоимости функции применяется градиентный спуск (Gradient Descent). Реализация градиентного бустинга в Scikit-Learn считается не такой эффективной, как в других библиотеках, например, в XGBoost, но она неплохо работает на маленьких датасетах и выдаёт достаточно точные прогнозы.

Вернёмся к гиперпараметрической настройке

В регрессии с помощью градиентного бустинга есть много гиперпараметров, которые нужно настраивать, за подробностями отсылаю вас к документации Scikit-Learn. Мы будем оптимизировать:

  • loss : минимизация функции потерь;
  • n_estimators : количество используемых слабых деревьев решений (decision trees);
  • max_depth : максимальная глубина каждого дерева решений;
  • min_samples_leaf : минимальное количество примеров, которые должны быть в «листовом» (leaf) узле дерева решений;
  • min_samples_split : минимальное количество примеров, которые нужны для разделения узла дерева решений;
  • max_features : максимальное количество признаков, которые используются для разделения узлов.

В этом коде мы создаём сетку из гиперпараметров, затем создаём объект RandomizedSearchCV и ищем с помощью 4-блочной перекрёстной проверки по 25 разным комбинациям гиперпараметров:

# Loss function to be optimized loss = ['ls', 'lad', 'huber'] # Number of trees used in the boosting process n_estimators = [100, 500, 900, 1100, 1500] # Maximum depth of each tree max_depth = [2, 3, 5, 10, 15] # Minimum number of samples per leaf min_samples_leaf = [1, 2, 4, 6, 8] # Minimum number of samples to split a node min_samples_split = [2, 4, 6, 10] # Maximum number of features to consider for making splits max_features = ['auto', 'sqrt', 'log2', None] # Define the grid of hyperparameters to search hyperparameter_grid = # Create the model to use for hyperparameter tuning model = GradientBoostingRegressor(random_state = 42) # Set up the random search with 4-fold cross validation random_cv = RandomizedSearchCV(estimator=model, param_distributions=hyperparameter_grid, cv=4, n_iter=25, scoring = 'neg_mean_absolute_error', n_jobs = -1, verbose = 1, return_train_score = True, random_state=42) # Fit on the training data random_cv.fit(X, y) After performing the search, we can inspect the RandomizedSearchCV object to find the best model: # Find the best combination of settings random_cv.best_estimator_ GradientBoostingRegressor(loss='lad', max_depth=5, max_features=None, min_samples_leaf=6, min_samples_split=6, n_estimators=500)

Эти результаты можно использовать для сеточного поиска, выбирая для сетки параметры, которые близки к этим оптимальным значениям. Но дальнейшая настройка вряд ли существенно улучшит модель. Есть общее правило: грамотное конструирование признаков окажет на точность модели куда большее влияние, чем самая дорогая гиперпараметрическая настройка. Это закон убывания доходности применительно к машинному обучению: конструирование признаков даёт наивысшую отдачу, а гиперпараметрическая настройка приносит лишь скромную выгоду.

Для изменения количества оценщиков (estimator) (деревьев решений) с сохранением значений других гиперпараметров можно поставить один эксперимент, который продемонстрирует роль этой настройки. Реализация приведена здесь, а вот что получилось в результате:

С ростом количества используемых моделью деревьев снижается уровень ошибок в ходе обучения и тестирования. Но ошибки при обучении снижаются куда быстрее, и в результате модель переобучается: показывает отличные результаты на обучающих данных, но на тестовых работает хуже.

На тестовых данных точность всегда снижается (ведь модель видит правильные ответы для учебного датасета), но существенное падение говорит о переобучении. Решить эту проблему можно с помощью увеличения объёма обучающих данных или уменьшения сложности модели с помощью гиперпараметров. Здесь мы не будем касаться гиперпараметров, но я рекомендую всегда уделять внимание проблеме переобучения.

Для нашей финальной модели мы возьмём 800 оценщиков, потому что это даст нам самый низкий уровень ошибки при перекрёстной проверке. А теперь протестируем модель!

Оценка с помощью тестовых данных

Будучи ответственными людьми мы удостоверились, что наша модель никоим образом не получала доступ к тестовым данным в ходе обучения. Поэтому точность при работе с тестовыми данными мы можем использовать в роли индикатора качества модели, когда её допустят к реальным задачам.

Скормим модели тестовые данные и вычислим ошибку. Вот сравнение результатов алгоритма градиентного бустинга по умолчанию и нашей настроенной модели:

# Make predictions on the test set using default and final model default_pred = default_model.predict(X_test) final_pred = final_model.predict(X_test) Default model performance on the test set: MAE = 10.0118. Final model performance on the test set: MAE = 9.0446.

Гиперпараметрическая настройка помогла улучшить точность модели примерно на 10 %. В зависимости от ситуации это может быть очень значительное улучшение, но требующее немало времени.

Сравнить длительность обучения обеих моделей можно с помощью волшебной команды %timeit в Jupyter Notebooks. Сначала измерим длительность работы модели по умолчанию:

%%timeit -n 1 -r 5 default_model.fit(X, y) 1.09 s ± 153 ms per loop (mean ± std. dev. of 5 runs, 1 loop each)

Одна секунда на обучение — очень прилично. А вот настроенная модель уже не такая шустрая:

%%timeit -n 1 -r 5 final_model.fit(X, y) 12.1 s ± 1.33 s per loop (mean ± std. dev. of 5 runs, 1 loop each)

Эта ситуация иллюстрирует фундаментальный аспект машинного обучения: всё дело в компромиссах. Постоянно приходится выбирать баланс между точностью и интерпретируемостью, между смещением и дисперсией, между точностью и временем работы, и так далее. Правильное сочетание полностью определяется конкретной задачей. В нашем случае 12-кратное увеличение длительности работы в относительном выражении велико, но в абсолютном — незначительно.

Мы получили финальные результаты прогнозирования, давайте теперь их проанализируем и выясним, есть ли какие-то заметные отклонения. Слева показан график плотности прогнозных и реальных значений, справа — гистограмма погрешности:

Прогноз модели неплохо повторяет распределение реальных значений, при этом на обучающих данных пик плотности расположен ближе к медианному значению (66), чем к реальному пику плотности (около 100). Погрешности имеют почти нормальное распределение, хотя есть несколько больших отрицательных значений, когда прогноз модели сильно отличается от реальных данных. В следующей статье мы подробнее рассмотрим интерпретирование результатов.

Заключение

В этой статье мы рассмотрели несколько этапов решения задачи машинного обучения:

  • Заполнение отсутствующих значений и масштабирование признаков.
  • Оценка и сравнение результатов работы нескольких моделей.
  • Гиперпараметрическая настройка с помощью случайного поиска по сетке и перекрёстной проверки.
  • Оценка лучшей модели с помощью тестовых данных.

В следующей статье мы постараемся разобраться, как работает наша модель. Также мы рассмотрим основные факторы, влияющие на балл Energy Star Score. Если мы знаем, что модель точна, и то попробуем понять, почему она прогнозирует именно так и что это говорит нам о самой задаче.

  • Блог компании NIX
  • Алгоритмы
  • Машинное обучение

Введение в машинное обучение в Python: Полное руководство с примерами

Введение в машинное обучение в Python: Полное руководство с примерами

Вы хотите сделать машинное обучение с помощью Python, но у вас возникли вопросы с чего начать? В этом уроке вы сделаете свой первый проект по машинному обучению с помощью Python. В уроке мы разберем шаг за шагом как:

  1. Скачать и установить Python SciPy и какие самые полезные пакеты для машинного обучения в Python.
  2. Загрузить датасет, поймем его структуру с помощью статистических методов и визуализируем данные
  3. Создадим 6 моделей машинного обучения, выберем лучшую и убедимся что точность модели является приемлемой

Если вы новичок в машинном обучении и хотите начать использовать Python, этот урок был разработан для вас.

Как начать использовать машинное обучение в Python?

Лучший способ научиться машинному обучению — проектировать и завершать небольшие проекты.

Python может быть пугающим при начале работы

Python является популярным и мощным интерпретируемым языком. В отличие от R, Python является и полным языком и платформой, которые можно использовать как для исследований, численных расчетов, так и для разработки производственных систем.

В Python есть также много модулей и библиотек на выбор, обеспечивая несколько способов выполнения каждой задачи.

Лучший способ начать использовать Python для машинного обучения — это разобрать готовый проект по машинному обучению и затем его сделать самому с нуля:

  • Это заставит вас установить и запустить Python интерпретатор.
  • Это даст вам понимание с высоты птичьего полета о том, как выглядит небольшой проект.
  • Это даст вам уверенность, чтобы перейти к собственным задача и проектам.

Новичкам нужен небольшой сквозной проект

Книги и курсы порой часто расстраивают. Они дают вам много теоретических конструкций и фрагментов, но вы никогда не увидите, как все они сочетаются друг с другом.

Когда вы применяете машинное обучение к собственному датасету, вы работаете над проектом. Проект по машинному обучению может быть не всегда последовательным, но обычно он имеет несколько выраженных этапов:

  • Постановка задачи
  • Подготовка данных
  • Оценка качества алгоритмов
  • Оптимизация результата
  • Презентация результата.

Лучший способ по-настоящему примириться с новой платформой или инструментом – это работать над проектом машинного обучения и покрыть эти ключевые этапы.

Если вы можете сделать это, у вас будет шаблон, который можно будет использовать в будущем на другой выборке данных или задаче. Вы сможете заполнить пробелы, такие как дальнейшая подготовка данных и улучшение алгоритмов.

«Hello World!» машинного обучения

Отличным примером небольшого проекта чтобы начать является задача классификация цветов (на примере цветов ириса).

Это хороший проект, потому что он легко интерпретируется.

  • Атрибуты данных являются числовыми, так что вы должны разобраться, как загрузить и обрабатывать данные
  • Это проблема классификации, позволяющая практиковаться с, возможно, более простым типом контролируемого алгоритма обучения
  • Задача является многоклассовой классификацией и может потребовать некоторой специализированной обработки
  • Выборка имеет только 4 атрибута и 150 строк, что означает, что она достаточно мала, легко будет обработана в операционном памяти локальном компьютера (и легко визуализировать на экране)
  • Все числовые атрибуты находятся в одном и том же масштабе и одинаковой шкале, не требуя специальной нормализации или масштабирования для начала работы

Давайте начнем проект «hello world» машинного обучения в Python.

Машинное обучение в Python (начало проекта)

Вот краткий обзор того, что мы собираемся охватить:

  • Установка платформы Python и SciPy
  • Загрузка датасета
  • Анализ датасета
  • Визуализация данных
  • Оценка алгоритмов машинного обучения
  • Прогнозирование данных

Не торопитесь, проработайте и поймете, что происходит на каждом шагу. Мы рекомендуем самостоятельно вводить команды.

Если у вас есть какие-либо вопросы, пожалуйста, задавайте их в чат.

1. Загрузка, установка и запуск Python и SciPy

Раздел для тех, у кого ее не установлен Python и SciPy. Мы не будем подробно останавливаться на том как устанавливать Python, есть много пошаговых руководств в интернете как это сделать или рекомендуем посетить раздел «Введение в Python».

1.1 Установка библиотек SciPy

Есть 5 ключевых библиотек, которые необходимо установить. Ниже приведен список библиотек Python SciPy, необходимых для этого руководства:

На сайте SciPy есть отличная инструкция по установке вышеуказанных библиотек на ключевых платформах: Windows, Linux, OS X mac. Если у вас есть какие-либо сомнения или вопросы, обратитесь к этому руководству, через него прошли миллионы людей.

Существует множество способов установить библиотеки. В качестве совета мы рекомендуем выбрать один метод и быть последовательным в установке каждой библиотеки. Если вы пользуетесь Windows или вы не уверены как это сделать, мы рекомендую установить бесплатную версию Anaconda, которая включает в себя все, что вам нужно (windows, macOS, Linux).

1.2 Запуск Python и проверка версий

Рекомендуется убедиться, что среда Python была успешно установлена и работает в штатном состоянии. Сценарий ниже поможет вам проверить вашу среду. Он импортирует каждую библиотеку, требуемую в этом учебнике, и печатает версию.

Откройте командную строку и запустите Python:

python

Мы рекомендуем работать непосредственно в интерпретаторе или писать скрипты и запускать их в командной строке, нежели редакторах и IDEs. Это позволит сосредоточиться на машинном обучении, а не инструментарии программиста.

Введите или скопируйте и вставьте следующий скрипт в интерпретатор:

# Проерка версий библиотек # Версия Python import sys print('Python: <>'.format(sys.version)) # Загрузка scipy import scipy print('scipy: <>'.format(scipy.__version__)) # Загрузка numpy import numpy print('numpy: <>'.format(numpy.__version__)) # Загрузка matplotlib import matplotlib print('matplotlib: <>'.format(matplotlib.__version__)) # Загрузка pandas import pandas print('pandas: <>'.format(pandas.__version__)) # Загрукзка scikit-learn import sklearn print('sklearn: <>'.format(sklearn.__version__))

Вот пример вывода:

Python: 3.7.0 (default, Jun 28 2018, 08:04:48) [MSC v.1912 64 bit (AMD64)] scipy: 1.1.0 numpy: 1.15.1 matplotlib: 2.2.3 pandas: 0.23.4 sklearn: 0.19.2

В идеале, ваши версии должны соответствовать или быть более поздними. API библиотек не меняются быстро, так что не не стоит переживать, если ваша версии другие. Все в этом урове, скорее всего, все еще будет работать для вас.

Если же выдает ошибку, рекомендуем обновить версионность системы. Если вы не можете запустить скрипт выше, вы не сможете пройти урок.

2. Загрузите данные

Мы будем использовать датасет цветов ирисов Фишера. Этот датасет известен тем, что он используется практически всеми в качестве «hello world» примера в машинном обучении и статистике.

Набор данных содержит 150 наблюдений за цветами ириса. В датасете есть четыре колонки измерений цветов в сантиметрах. Пятая колонна является видом наблюдаемого цветка.

Все наблюдаемые цветы принадлежат к одному из трех видов. Узнать больше об этом датасете можно в Википедия.

На этом этапе мы загрузим данные из URL-адреса в CSV файл.

2.1 Импорт библиотек

Во-первых, давайте импортировать все модули, функции и объекты, которые мы планируем использовать в этом уроке.

# Загрузка библиотек from pandas import read_csv from pandas.plotting import scatter_matrix from matplotlib import pyplot from sklearn.model_selection import train_test_split from sklearn.model_selection import cross_val_score from sklearn.model_selection import StratifiedKFold from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC

Все должно загружаться без ошибок. Если у вас есть ошибка, остановитесь. Перед продолжением необходима рабочая среда SciPy. Посмотрите совет выше о настройке вашей среды.

2.2 Загрузка датасета

Мы можем загрузить данные непосредственно из репозитория машинного обучения UCI.

Мы используем модуль pandas для загрузки данных. Мы также будем использовать pandas чтобы исследовать данные как целей описательной статистики, так для визуализации данных.

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

# Загрузка датасета url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names)

Датасет должен загрузиться без происшествий.

Если у вас есть проблемы с сетью, вы можете скачать файл iris.csv в рабочую директорию и загрузить его с помощью того же метода, изменив URL на локальное имя файла.

3. Анализ датасета

Теперь пришло время взглянуть на данные более детально. На этом этапе мы погрузимся в анализ данные несколькими способами:

  • Размерность датасета
  • Просмотр среза данных
  • Статистическая сводка атрибутов
  • Разбивка данных по атрибуту класса.

Не волнуйтесь, каждый взгляд на данные является одной командой. Это полезные команды, которые можно использовать снова и снова в будущих проектах.

3.1 Размерность датасета

Мы можем получить быстрое представление о том, сколько экземпляров (строк) и сколько атрибутов (столбцов) содержится в датасете с помощью метода shape.

# shape print(dataset.shape)

Вы должны увидеть 150 экземпляров и 5 атрибутов:

(150, 5)

3.2 Просмотр среза данных

Исследовании данных, стоит сразу в них заглянуть, для этого есть метод head()

# Срез данных head print(dataset.head(20))

Это должно вывести первые 20 строк датасета.

 sepal-length sepal-width petal-length petal-width class 0 5.1 3.5 1.4 0.2 Iris-setosa 1 4.9 3.0 1.4 0.2 Iris-setosa 2 4.7 3.2 1.3 0.2 Iris-setosa 3 4.6 3.1 1.5 0.2 Iris-setosa 4 5.0 3.6 1.4 0.2 Iris-setosa 5 5.4 3.9 1.7 0.4 Iris-setosa 6 4.6 3.4 1.4 0.3 Iris-setosa 7 5.0 3.4 1.5 0.2 Iris-setosa 8 4.4 2.9 1.4 0.2 Iris-setosa 9 4.9 3.1 1.5 0.1 Iris-setosa 10 5.4 3.7 1.5 0.2 Iris-setosa 11 4.8 3.4 1.6 0.2 Iris-setosa 12 4.8 3.0 1.4 0.1 Iris-setosa 13 4.3 3.0 1.1 0.1 Iris-setosa 14 5.8 4.0 1.2 0.2 Iris-setosa 15 5.7 4.4 1.5 0.4 Iris-setosa 16 5.4 3.9 1.3 0.4 Iris-setosa 17 5.1 3.5 1.4 0.3 Iris-setosa 18 5.7 3.8 1.7 0.3 Iris-setosa 19 5.1 3.8 1.5 0.3 Iris-setosa

3.3 Статистическая сводка

Давайте взглянем теперь на статистическое резюме каждого атрибута. Статистическая сводка включает в себя количество экземпляров, их среднее, мин и макс значения, а также некоторые процентили.

# Стастические сводка методом describe print(dataset.describe()) 

Мы видим, что все численные значения имеют одинаковую шкалу (сантиметры) и аналогичные диапазоны от 0 до 8 сантиметров.

 sepal-length sepal-width petal-length petal-width count 150.000000 150.000000 150.000000 150.000000 mean 5.843333 3.054000 3.758667 1.198667 std 0.828066 0.433594 1.764420 0.763161 min 4.300000 2.000000 1.000000 0.100000 25% 5.100000 2.800000 1.600000 0.300000 50% 5.800000 3.000000 4.350000 1.300000 75% 6.400000 3.300000 5.100000 1.800000 max 7.900000 4.400000 6.900000 2.500000

3.4 Распределение классов

Давайте теперь рассмотрим количество экземпляров (строк), которые принадлежат к каждому классу. Мы можем рассматривать это как абсолютный счет.

# Распределение по атрибуту class print(dataset.groupby('class').size())

Мы видим, что каждый класс имеет одинаковое количество экземпляров (50 или 33% от датасета).

class Iris-setosa 50 Iris-versicolor 50 Iris-virginica 50 dtype: int64

3.5 Резюме загрузки датасета

На будущее мы можем объединить все предыдущие элементы вместе в один скрипт..

# Загрузка библиотек from pandas import read_csv # Загрузка датасета url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # shape print(dataset.shape) # Срез данных head print(dataset.head(20)) # Стастические сводка методом describe print(dataset.describe()) # Распределение по атрибуту class print(dataset.groupby('class').size())

4. Визуализация данных

Теперь когда у нас есть базовое представление о данных, давайте расширим его с помощью визуализаций.

Мы рассмотрим два типа графиков:

  • Одномерные (Univariate) графики, чтобы лучше понять каждый атрибут.
  • Многомерные (Multivariate) графики, чтобы лучше понять взаимосвязь между атрибутами.

4.1 Одномерные графики

Начнем с некоторых одномерных графиков, то есть графики каждой отдельной переменной. Учитывая, что входные переменные являются числовыми, мы можем создавать диаграмма размаха (или «ящик с усами», по-английски «box and whiskers diagram») каждого из них.

# Диаграмма размаха dataset.plot(kind='box', subplots=True, layout=(2,2), sharex=False, sharey=False) pyplot.show()

Это дает нам более четкое представление о распределении атрибутов на входе.

Мы также можем создать гистограмму входных данных каждой переменной, чтобы получить представление о распределении.

# Гистограмма распределения атрибутов датасета dataset.hist() pyplot.show()

Из графиков видно, что две из входных переменных имеют около гауссово (нормальное) распределение. Это полезно отметить, поскольку мы можем использовать алгоритмы, которые могут использовать это предположение.

4.2 Многомерные графики

Теперь мы можем посмотреть на взаимодействия между переменными.

Во-первых, давайте посмотрим на диаграммы рассеяния всех пар атрибутов. Это может быть полезно для выявления структурированных взаимосвязей между входными переменными.

#Матрица диаграмм рассеяния scatter_matrix(dataset) pyplot.show()

Обратите внимание на диагональ некоторых пар атрибутов. Это говорит о высокой корреляции и предсказуемой взаимосвязи.

4.3 Резюме визуализации данных

Для справки мы можем связать все предыдущие элементы вместе в один скрипт. Полный пример приведен ниже.

# Загрузка библиотек from pandas import read_csv # Загрузка датасета url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # Диаграмма размаха dataset.plot(kind='box', subplots=True, layout=(2,2), sharex=False, sharey=False) pyplot.show() # Гистограмма распределения атрибутов датасета dataset.hist() pyplot.show() #Матрица диаграмм рассеяния scatter_matrix(dataset) pyplot.show()

5. Оценка алгоритмов

Теперь пришло время создать некоторые модели данных и оценить их точность на контрольных данных.

Вот что мы собираемся охватить в этом шаге:

  • Отделим обучающая выборка от контрольной (тестовой) выборке.
  • Настройка 10-кратной кросс-валидации
  • Построим несколько различных моделей для прогнозирования класса цветка из измерений цветов
  • Выберем лучшую модель.

5.1 Создание контрольной выборки

Мы должны знать, что модель, которую мы создали, хороша.

Позже мы будем использовать статистические методы для оценки точности моделей. Мы также хотим получить более конкретную оценку точности наилучшей модели на контрольных данных, оценив ее по фактических контрольным данным.

То есть, мы собираемся удержать некоторые данные, на которых алгоритмы не будут обучаться, и мы будем использовать эти данные, чтобы получить второе и независимое представление о том, насколько точной может быть лучшая модель на самом деле.

Разделим загруженный датасет на два:

  • 80% данных мы будем использовать для обучения, оценки и выбора лучшей среди наших моделей
  • 20% данных, что мы будем использовать в качестве контрольного теста качества полученных моделей
# Разделение датасета на обучающую и контрольную выборки array = dataset.values # Выбор первых 4-х столбцов X = array[:,0:4] # Выбор 5-го столбца y = array[:,4] # Разделение X и y на обучающую и контрольную выборки X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1)

Теперь у вас есть обучающиеся данные в X_train и Y_train для подготовки моделей и контрольная выборка X_validation и Y_validation, которые мы можем использовать позже.

Обратите внимание, что мы использовали срез в Python для выбора столбцов в массиве NumPy.

5.2 Тестирование проверки

Для оценки точности модели мы будем использовать стратифицированную 10-кратную кросс-валидацию.

Это разделит наш датасет на 10 частей, обучающийся на 9 частях и 1 тестовой проверке и будет повторять обучение на всех комбинаций из выборок train-test.

Стратифицированная означает, что каждый прогон по выборке данных будет стремиться иметь такое же распределение примера по классу, как это существует во всем наборе обучаемых данных.

Для получения дополнительной информации о том как работает метод k-fold кросс-валидации можно посмотреть по ссылке.

Мы устанавливаем случайное затравку через random_state аргумент на фиксированное число, чтобы гарантировать, что каждый алгоритм оценивается на тех же выборках обучающихся данных. Конкретные случайные затравки не имеет значения.

Мы используем метрику «acccuracy» для оценки моделей.

Это соотношение числа правильно предсказанных экземпляров, разделенных на общее количество экземпляров в наборе данных, умноженном на 100, чтобы дать процент (например, точность 95%). Мы будем использовать оценочную переменную, когда мы будем запускать сборку и оценивать каждую модель.

5.3 Строим модели машинного обучения

Мы не знаем, какие алгоритмы будет хороши для этой задачи или какие конфигурации их использовать.

Все что увидела выше, что некоторые классы частично линейно зависят в некоторых измерениях, поэтому в целом ожидаем хорошие результаты.

Давайте протестируем 6 различных алгоритмов:

  • Логистическая регрессия или логит-модель (LR)
  • Линейный дискриминантный анализ (LDA)
  • Метод k-ближайших соседей (KNN)
  • Классификация и регрессия с помощью деревьев (CART)
  • Наивный байесовский классификатор (NB)
  • Метод опорных векторов (SVM)

Здесь приведена смесь простых линейных (LR и LDA), нелинейных (KNN, CART, NB и SVM) алгоритмов.

Давайте построим и оценим наши модели:

# Загружаем алгоритмы модели models = [] models.append(('LR', LogisticRegression(solver='liblinear', multi_class='ovr'))) models.append(('LDA', LinearDiscriminantAnalysis())) models.append(('KNN', KNeighborsClassifier())) models.append(('CART', DecisionTreeClassifier())) models.append(('NB', GaussianNB())) models.append(('SVM', SVC(gamma='auto'))) # оцениваем модель на каждой итерации results = [] names = [] for name, model in models: kfold = StratifiedKFold(n_splits=10, random_state=1, shuffle=True) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring='accuracy') results.append(cv_results) names.append(name) print('%s: %f (%f)' % (name, cv_results.mean(), cv_results.std()))

5.4 Выбираем модель

Теперь у нас есть 6 моделей и оценки точности каждой из них. Мы должны сравнить модели друг с другом и выбрать наиболее точные.

Запустив приведенный выше пример, мы получим следующие необработанные результаты:

LR: 0.955909 (0.044337) LDA: 0.975641 (0.037246) KNN: 0.950524 (0.040563) CART: 0.951166 (0.052812) NB: 0.951166 (0.052812) SVM: 0.983333 (0.033333)

Обратите внимание, что ваши результаты могут немного варьироваться, учитывая стохастический характер алгоритмов обучения.

Как интерпретировать полученные значения качества моделей?

В этом случае, мы видим, что это выглядит как метод опорных векторов (SVM) имеет самый большой расчет точности около 0,98 или 98%.

Мы также можем создать график результатов оценки модели и сравнить расхождение средней точность каждой модели. Существует разбор показателей точности для каждого алгоритма, потому что каждый алгоритм был оценен 10 раз (в рамках 10-кратной кросс-валидации).

Хороший способ сравнить результаты для каждого алгоритма заключается в создании диаграмме размаха атрибутов выходных данных и их усов для каждого распределения и сравнения распределений.

# Сравниванием алгоритмы pyplot.boxplot(results, labels=names) pyplot.title('Algorithm Comparison') pyplot.show()

Мы видим, что ящики и усы участков в верхней части диапазона достигают 100% точности, а некоторые находятся в районе 85% точности.

5.5 Резюме оценки алгоритмов

Для справки мы можем связать все предыдущие элементы вместе в один скрипт. Полный пример приведен ниже.

# Загрузка библиотек from pandas import read_csv from pandas.plotting import scatter_matrix from matplotlib import pyplot from sklearn.model_selection import train_test_split from sklearn.model_selection import cross_val_score from sklearn.model_selection import StratifiedKFold from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score from sklearn.linear_model import LogisticRegression from sklearn.tree import DecisionTreeClassifier from sklearn.neighbors import KNeighborsClassifier from sklearn.discriminant_analysis import LinearDiscriminantAnalysis from sklearn.naive_bayes import GaussianNB from sklearn.svm import SVC # Загрузка датасета url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # Разделение датасета на обучающую и контрольную выборки array = dataset.values # Выбор первых 4-х столбцов X = array[:,0:4] # Выбор 5-го столбца y = array[:,4] # Разделение X и y на обучающую и контрольную выборки X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1) # Загружаем алгоритмы моделей models = [] models.append(('LR', LogisticRegression(solver='liblinear', multi_class='ovr'))) models.append(('LDA', LinearDiscriminantAnalysis())) models.append(('KNN', KNeighborsClassifier())) models.append(('CART', DecisionTreeClassifier())) models.append(('NB', GaussianNB())) models.append(('SVM', SVC(gamma='auto'))) # оцениваем модель на каждой итерации results = [] names = [] for name, model in models: kfold = StratifiedKFold(n_splits=10, random_state=1, shuffle=True) cv_results = cross_val_score(model, X_train, Y_train, cv=kfold, scoring='accuracy') results.append(cv_results) names.append(name) print('%s: %f (%f)' % (name, cv_results.mean(), cv_results.std())) # Сравниванием алгоритмы pyplot.boxplot(results, labels=names) pyplot.title('Algorithm Comparison') pyplot.show()

6. Прогнозирование данных

Прежде чем что-либо прогнозировать необходимо выбрать алгоритм для прогнозирования. По результатам оценки моделей предыдущего раздела мы выбрали модель SVM как наиболее точную. Мы будем использовать эту модель в качестве нашей конечной модели.

Теперь мы хотим получить представление о точности модели на нашей контрольной выборке данных.

Это даст нам независимую окончательную проверку точности лучшей модели. Полезно сохранить контрольную выборку для случаев когда была допущена ошибки в процессе обучения, такая как переобучение или утечка данных. Обе эти проблемы могут привести к чрезмерно оптимистичному результату.

6.1 Создаем прогноз

Мы можем протестировать модель на всей выборке обучаемых данных и сделать прогноз на контрольной выборке.

# Создаем прогноз на контрольной выборке model = SVC(gamma='auto') model.fit(X_train, Y_train) predictions = model.predict(X_validation)

6.2 Оцениваем прогноз

Мы можем оценить прогноз, сравнив его с ожидаемым результатом контрольной выборки, а затем вычислить точность классификации, а также матрицу ошибок и отчет о классификации.

# Оцениваем прогноз print(accuracy_score(Y_validation, predictions)) print(confusion_matrix(Y_validation, predictions)) print(classification_report(Y_validation, predictions))

Мы видим, что точность 0,966 или около 96% на контрольной выборке.

Матрица ошибок дает представление об одной допущенной ошибке (сумма недиагональных значений).

Наконец, отчет о классификации предусматривает разбивку каждого класса по точности (precision), полнота (recall), f1-оценка, показывающим отличные результаты (при этом контрольная выборка была небольшая, всего 30 значений).

0.9666666666666667 [[11 0 0] [ 0 12 1] [ 0 0 6]] precision recall f1-score support Iris-setosa 1.00 1.00 1.00 11 Iris-versicolor 1.00 0.92 0.96 13 Iris-virginica 0.86 1.00 0.92 6 avg / total 0.97 0.97 0.97 30 

6.3 Резюме прогнозирование данных

Для справки мы можем связать все предыдущие элементы вместе в один скрипт. Полный пример приведен ниже.

# Загрузка библиотек from pandas import read_csv from sklearn.model_selection import train_test_split from sklearn.metrics import classification_report from sklearn.metrics import confusion_matrix from sklearn.metrics import accuracy_score # Загрузка датасета url = "https://raw.githubusercontent.com/jbrownlee/Datasets/master/iris.csv" names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] dataset = read_csv(url, names=names) # Разделение датасета на обучающую и контрольную выборки array = dataset.values # Выбор первых 4-х столбцов X = array[:,0:4] # Выбор 5-го столбца y = array[:,4] # Разделение X и y на обучающую и контрольную выборки X_train, X_validation, Y_train, Y_validation = train_test_split(X, y, test_size=0.20, random_state=1) # Создаем прогноз на контрольной выборке model = SVC(gamma='auto') model.fit(X_train, Y_train) predictions = model.predict(X_validation) # Оцениваем прогноз print(accuracy_score(Y_validation, predictions)) print(confusion_matrix(Y_validation, predictions)) print(classification_report(Y_validation, predictions))

Машинное обучение в Python это не сложно

Проработайте примеры из урока, это не займет дольше 10-15 минут.

Вам не обязательно сразу все понимать. Ваша цель состоит в том, чтобы запустить ряд скриптов описанных в уроке и получить конечный результат. Вам не нужно понимать все при первом проходе. Записывайте свои вопросы параллельно с тем как пишите код. Рекомендуем использовать справку («FunctionName») в Python чтобы разобраться глубже во всех функциях, которые вы используете.

Вам не нужно знать, как работают алгоритмы. Важно знать об ограничениях и о том, как настроить алгоритмы машинного обучения. Более подробное узнать о конкретных алгоритмах можно и позже. Вы должны постепенно накапливать знания о работе алгоритмы. Сегодня, начните с того что поймете как его использовать в Python.

Вам не нужно быть программистом Python. Синтаксис языка Python может быть интуитивно понятным, даже если вы новичок в нем. Как и на других языках, сосредоточьтесь на вызовах функций (например,function()) и назначениях (например, a = «b»). Если вы являетесь разработчиком, вы итак уже знаете, как подобрать основы языка очень быстро.

Вам не нужно быть экспертом по машинного обучению. Вы можете узнать о преимуществах и ограничениях различных алгоритмов гораздо позже, и есть много информации в интернете, о более глубинных тонкостях алгоритмов и этапах проекта машинного обучения и важности оценки точности с помощью перекрестной валидации.

Итого

Вы сделали свой первый мини-проект по машинному обучению в Python.

Вы наверняка обнаружили, что после завершения даже небольшого проекта от загрузки данных до прогнозирования — вы уже намного сильнее продвинулись.

Какие могут быть следующие шаги по изучению машинного обучения?

Мы не освещали все этапы проекта машинного обучения, потому что это ваш первый проект, и нам нужно сосредоточиться на ключевых этапах. А именно, загрузке данных, анализе данных, оценка некоторых алгоритмов и прогнозировании данных. В других уроках мы рассмотрим другие аспекты машинного обучения по подготовке данных и улучшению результатов.

Машинное обучение для школьников (заметки)

Посвящается Михаилу Абрамовичу Ройтбергу
(27.12.1952 — 16.08.2017), моему учителю и потрясающему человеку, который заразил меня преподаванием.

Занятие #5 (13.08.2016): Модель регрессии, бустинг и принцип репки

Курс «Экосистема Python и Машинное Обучение» проводился в рамках школы молекулярной и теоретической биологии,
Barcelona Biomedical Research Park, Барселона, Испания.

Целью занятия является создание программы, способной предсказать цену дома по ряду его известных характеристик. Такие программы мы называем моделью регрессии (см. ниже). Модель регрессии будем создавать в виде блокнота (Jupyter notebook) с помощью библиотеки SKLearn. Ниже каждый раздел текста соответствует очередной ячейке блокнота и небольшому заданию на языке программирования Python (в русском языке распространено название Питон или Пайтон).

Замечание. В машинном обучении (Machine Learning) есть несколько типовых задач — задачи классификации и задачи регрессии.
1. В задачах классификации нужно уметь «классифицировать» новый объект к одному из классов. Например, определить кто изображен на фотографии — «кошка» или «собака». Для решения такой задачи будет строиться модель классификации (или классификатор);
2. В задачах регрессии нам нужно предсказать численное значение. Примеры: предсказать цену дома в зависимости от его характеристик; количество лайков Вашего поста в социальных сетях; вероятность поступить в конкретных ВУЗ на бюджет на основе успеваемости и посещаемости. Для решения таких задач будет строиться модель регрессии. Слово регрессор имеет много смыслов, поэтому для однозначности мы будем использовать именно «модель регрессии» (но не «регрессор» / regressor).

Disclamer. Заметки не покрывают весь материал занятия, содержат ряд неточностей и местами требуют дополнительных комментариев, автор обязательно к ним вернется и будет благодарен Вашим дополнениям.


Conference, Machine Learning and Very Large Data Sets

1st October, 2013, Moscow, Russia

1. Библиотеки Python для занятия

  • matplotlib — библиотека для рисования графиков (очень удобно для визуализации данных или результатов экспериментов)
  • numpy — библиотека для эффективной работы с матрицами (одномерные массивы, двумерные, …, многомерные)
  • pandas — «Excel» для Python (удобно для анализа «табличных» данных, расчета базовых статистик)
  • sklearn — набор алгоритмов (классификаторов, моделей регрессии, …) для решения задач машинного обучения. Например, на занятии рассмотрим GradientBoostingRegressor — бустинг на решающих деревьях
  • https://colab.research.google.com/
import matplotlib import numpy import pandas import sklearn print("Все отлично работает!")

2. Наборы данных

Питон содержит много наборов данных (datasets). Доступ к ним возможен с помощью модуля datasets. Загрузим набор данных «boston» с ценами на дома в городе Бостон:

from sklearn import datasets boston = datasets.load_boston() print(boston.DESCR)

На экране Вы увидите содержание набора данных (см. ПРИЛОЖЕНИИ 1.). Среди характеристик будут такие показатели как транспортная доступность, расстояние до реки и т.п.

3. Подготовка данных для проведения эксперимента

Данные нужно:
1. Перемешать;
2. И разделить на обучающую и тестовую выборку (train and test parts)

Выделение тестового набора (п. 2) необходимо по следующим соображениям. Если мы будем проверять модель на тех же самых данных, на которых ее обучали (отсюда и понятие «машинное обучение»), то оптимальной (лучшей) стала бы модель, которая просто запомнит правильные ответы ;). Именно поэтому проверять результаты обучения (модели) необходимо на наборе данных, который не пересекается с набором данных, на котором проходило обучение

Перемешивать (п. 1) нужно, чтобы избежать проблем в обучении, связанных с возможной структуризацией данных в исходном наборе данных. Например, если в задаче классификации сначала идут изображения с «кошками», а только затем с «собаками», то учиться мы будем только по фотографиям кошек, а проверять только на фотографиях с собаками. Или представьте, что вы готовились к контрольной по физике, а когда пришли на занятие вам дали контрольную по химии. Немного нечестно, неправда ли?

from sklearn.model_selection import train_test_split X_train, X_test, y_train, y_test = train_test_split(boston.data, boston.target, random_state=100500, train_size=0.9)

В данном случае у нас 90% данных используется для обучения модели регрессии, а 10% для оценки качества. train_test_split перемешивает данные и делит данные на выборки train и test.

4. Контейнер для модели регрессии

Сделаем «заготовку модели регрессии». По научному эта заготовка называется «контейнер«. В контейнере описывается общий алгоритм построения модели регрессии. В нашем случае — это алгоритм BoostingRegressor (см. ПРИЛОЖЕНИЕ 2). Установим значения параметров для обучения n_estimators, max_depth, min_samples_split, learning_rate, loss :

from sklearn.ensemble import GradientBoostingRegressor regression_model = GradientBoostingRegressor(loss="ls", learning_rate=0.1, n_estimators=100, max_depth=3, min_samples_split=2)

5. Обучение модели регрессии и проверка качества предсказания

Обучение модели регрессии производится с помощью функции fit, а предсказание с помощью обученной модели — с помощью функции predict. Эти функции существуют для любых моделей регрессии и классификации, поддерживаемых библиотекой SKLearn.

Вдаваться в детали процесса обучения мы не будем. Отдельно отметим важность способа сравнения результатов. Выбор способа для сравнения моделей зависит от решаемой задачи и существенно влияет на результаты обучения. В качестве примеров укажем средне-квадратичное отклонение (квадрат «евклидова расстояния») эталонного и предсказанного набора результатов, а также максимальное отклонение предсказанного результата от соответствующего эталона.

from sklearn.metrics import mean_squared_error, mean_absolute_error regression_model.fit(X_train, y_train) y_predicted = regression_model.predict(X_test) print("mean squared error: ", mean_squared_error(y_test, y_predicted)) print("mean absolute error: ", mean_absolute_error(y_test, y_predicted)) print("max absolute distance: ", numpy.abs(y_test - y_predicted).max())

ПРИЛОЖЕНИЕ 1. Описание набора данных «Бостон»

Boston House Prices dataset
Notes

——
Data Set Characteristics:
:Number of Instances: 506
:Number of Attributes: 13 numeric/categorical predictive
:Median Value (attribute 14) is usually the target

:Attribute Information (in order):
— CRIM per capita crime rate by town
— ZN proportion of residential land zoned for lots over 25,000 sq.ft.
— INDUS proportion of non-retail business acres per town
— CHAS Charles River dummy variable (= 1 if tract bounds river; 0 otherwise)
— NOX nitric oxides concentration (parts per 10 million)
— RM average number of rooms per dwelling
— AGE proportion of owner-occupied units built prior to 1940
— DIS weighted distances to five Boston employment centres
— RAD index of accessibility to radial highways
— TAX full-value property-tax rate per $10,000
— PTRATIO pupil-teacher ratio by town
— B 1000(Bk — 0.63)^2 where Bk is the proportion of blacks by town
— LSTAT % lower status of the population
— MEDV Median value of owner-occupied homes in $1000’s

:Missing Attribute Values: None

:Creator: Harrison, D. and Rubinfeld, D.L. This is a copy of UCI ML housing dataset.

http://archive.ics.uci.edu/ml/datasets/Housing
This dataset was taken from the StatLib library which is maintained at Carnegie
Mellon University.

The Boston house-price data of Harrison, D. and Rubinfeld, D.L. ‘Hedonic prices and the demand for clean air’, J. Environ. Economics & Management, vol.5, 81-102, 1978. Used in Belsley, Kuh & Welsch, ‘Regression diagnostics . ‘, Wiley, 1980. N.B. Various transformations are used in the table on pages 244-261 of the latter.

The Boston house-price data has been used in many machine learning papers that address regression problems.

References:
— Belsley, Kuh & Welsch, ‘Regression diagnostics: Identifying Influential Data and Sources of Collinearity’, Wiley, 1980. 244-261.
— Quinlan,R. (1993). Combining Instance-Based and Model-Based Learning. In Proceedings on the Tenth International Conference of Machine Learning, 236-243,
University of Massachusetts, Amherst. Morgan Kaufmann.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *