Изучение контролируемых алгоритмов машинного обучения

Опубликовано: 2022-03-11

Основная цель этого чтения — понять достаточную статистическую методологию, чтобы иметь возможность использовать алгоритмы машинного обучения в библиотеке Python scikit-learn, а затем применить эти знания для решения классической задачи машинного обучения.

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

Некоторые отказы от ответственности:

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

С этим отмеченным, давайте погрузимся!

Краткое введение в алгоритмы машинного обучения

Как только вы начинаете заниматься этой областью, вы понимаете, что машинное обучение менее романтично, чем вы думаете. Поначалу я был полон надежд, что после того, как я узнаю больше, я смогу создать свой собственный ИИ Jarvis, который будет целыми днями кодировать программное обеспечение и зарабатывать деньги для меня, чтобы я мог проводить целые дни на открытом воздухе, читая книги, управляя мотоциклом, и наслаждаюсь безрассудным образом жизни, в то время как мой личный Джарвис делает мои карманы глубже. Однако вскоре я понял, что в основе алгоритмов машинного обучения лежит статистика, которую лично я нахожу скучной и неинтересной. К счастью, оказалось, что «скучная» статистика имеет весьма интересные приложения.

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

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

Тем не менее, мне было любопытно посмотреть, смогу ли я использовать алгоритмы машинного обучения для поиска зависимостей в криптографических хеш-функциях (SHA, MD5 и т. д.), однако на самом деле вы не можете этого сделать, потому что правильные криптопримитивы построены таким образом. что они устраняют зависимости и производят значительно труднопредсказуемый результат. Я считаю, что за бесконечное количество времени алгоритмы машинного обучения могут взломать любую криптомодель.

К сожалению, у нас не так много времени, поэтому нам нужно найти другой способ эффективного майнинга криптовалюты. Как далеко мы продвинулись до сих пор?

Краткая история алгоритмов машинного обучения

Корни алгоритмов машинного обучения восходят к Томасу Байесу, английскому статистику, жившему в 18 веке. Его статья «Опыт решения проблемы доктрины случайностей » лежит в основе теоремы Байеса, которая широко применяется в области статистики.

В 19 веке Пьер-Симон Лаплас опубликовал аналитическую теорию вероятностей , расширив работу Байеса и определив то, что мы знаем сегодня как теорему Байеса. Незадолго до этого Адриан-Мари Лежандр описал метод «наименьших квадратов», также широко используемый сегодня в обучении с учителем.

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

Но потом, в 1970-е, идея ИИ вызвала много пессимизма — и, следовательно, финансирование сократилось, — поэтому этот период называют зимой ИИ . Повторное открытие обратного распространения в 1980-х годах вызвало возрождение исследований в области машинного обучения. И сегодня это снова актуальная тема.

Покойный Лео Брейман различал две парадигмы статистического моделирования: моделирование данных и алгоритмическое моделирование. «Алгоритмическое моделирование» означает более или менее алгоритмы машинного обучения, такие как случайный лес .

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

Категории алгоритмов машинного обучения

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

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

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

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

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

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

Основные модели контролируемого машинного обучения

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

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

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

Как уже упоминалось выше, большинство алгоритмов машинного обучения работают, находя статистическую зависимость в предоставленных им данных. Эта зависимость называется гипотезой и обычно обозначается $h(\theta)$.

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

 import matplotlib.pyplot as plt from pandas import read_csv import os # Load data data_path = os.path.join(os.getcwd(), "data/blood-pressure.txt") dataset = read_csv(data_path, delim_whitespace=True) # We have 30 entries in our dataset and four features. The first feature is the ID of the entry. # The second feature is always 1. The third feature is the age and the last feature is the blood pressure. # We will now drop the ID and One feature for now, as this is not important. dataset = dataset.drop(['ID', 'One'], axis=1) # And we will display this graph %matplotlib inline dataset.plot.scatter(x='Age', y='Pressure') # Now, we will assume that we already know the hypothesis and it looks like a straight line h = lambda x: 84 + 1.24 * x # Let's add this line on the chart now ages = range(18, 85) estimated = [] for i in ages: estimated.append(h(i)) plt.plot(ages, estimated, 'b')

[<matplotlib.lines.Line2D at 0x11424b828>]

Линейная гипотеза, показанная на графике зависимости возраста от артериального давления.

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

Чтобы решить эту задачу, нам нужно узнать зависимость между $x$ и $y$, которая обозначается как $y = f(x)$. Следовательно, $f(x)$ — идеальная целевая функция. Алгоритм машинного обучения попытается угадать функцию гипотезы $h(x)$, которая является ближайшим приближением к неизвестной $f(x)$.

Простейшая возможная форма гипотезы для задачи линейной регрессии выглядит так: $h_\theta(x) = \theta_0 + \theta_1 * x$. У нас есть одна входная скалярная переменная $x$, которая выводит одну скалярную переменную $y$, где $\theta_0$ и $\theta_1$ — параметры, которые нам нужно изучить. Процесс подгонки этой синей линии к данным называется линейной регрессией. Важно понимать, что у нас всего один входной параметр $x_1$; однако многие функции гипотез также включают единицу смещения ($x_0$). Итак, наша результирующая гипотеза имеет вид $h_\theta(x) = \theta_0 * x_0 + \theta_1 * x_1$. Но мы можем не писать $x_0$, потому что это почти всегда равно 1.

Возвращаемся к синей линии. Наша гипотеза выглядит так: $h(x) = 84 + 1,24x$, что означает, что $\theta_0 = 84$ и $\theta_1 = 1,24$. Как мы можем автоматически получить эти значения $\theta$?

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

\[J(\theta) = \frac{1}{2m}\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i)})^2\ ]

Например, наша гипотеза предсказывает, что для 48-летнего человека артериальное давление должно быть $h(48) = 84 + 1,24 * 48 = 143 мм рт.ст.$; однако в нашей обучающей выборке мы имеем значение $130 мм рт.ст.$. Следовательно, ошибка $(143 - 130)^2 = 169$. Теперь нам нужно вычислить эту ошибку для каждой отдельной записи в нашем наборе обучающих данных, а затем просуммировать ее вместе ($\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i )})^2$) и взять из этого среднее значение.

Это дает нам одно скалярное число, которое представляет собой стоимость функции. Наша цель — найти такие значения $\theta$, чтобы функция стоимости была наименьшей; другими словами, мы хотим минимизировать функцию стоимости. Надеюсь, это покажется интуитивно понятным: если у нас небольшое значение функции стоимости, это означает, что ошибка прогноза также мала.

 import numpy as np # Let's calculate the cost for the hypothesis above h = lambda x, theta_0, theta_1: theta_0 + theta_1 * x def cost(X, y, t0, t1): m = len(X) # the number of the training samples c = np.power(np.subtract(h(X, t0, t1), y), 2) return (1 / (2 * m)) * sum(c) X = dataset.values[:, 0] y = dataset.values[:, 1] print('J(Theta) = %2.2f' % cost(X, y, 84, 1.24))

J(Theta) = 1901.95

Теперь нам нужно найти такие значения $\theta$, чтобы значение нашей функции стоимости было минимальным. Но как мы это делаем?

\[minJ(\theta) = \frac{1}{2m}\sum_{i=1}^m(h_\theta(x^{(i)}) - y^{(i)})^2\ ]

Существует несколько возможных алгоритмов, но наиболее популярным является градиентный спуск . Чтобы понять интуицию, стоящую за методом градиентного спуска, давайте сначала нанесем его на график. Для простоты примем более простую гипотезу $h(\theta) = \theta_1 * x$. Далее мы построим простую двумерную диаграмму, где $x$ — это значение $\theta$, а $y$ — функция стоимости в этой точке.

 import matplotlib.pyplot as plt fig = plt.figure() # Generate the data theta_1 = np.arange(-10, 14, 0.1) J_cost = [] for t1 in theta_1: J_cost += [ cost(X, y, 0, t1) ] plt.plot(theta_1, J_cost) plt.xlabel(r'$\theta_1$') plt.ylabel(r'$J(\theta)$') plt.show() 

Выпуклая функция стоимости.

Функция стоимости выпуклая, а это означает, что на интервале $[a, b]$ есть только один минимум. Что опять же означает, что наилучшие параметры $\theta$ находятся в точке, где функция стоимости минимальна.

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

Нахождение минимума функции стоимости.

Если мы вычислим производную функции гипотезы в определенной точке, это даст нам наклон касательной к кривой в этой точке. Это означает, что мы можем рассчитать наклон в каждой точке графика.

Алгоритм работы такой:

  1. Мы выбираем случайную начальную точку (случайный $\theta$).
  2. Вычислите производную функции стоимости в этой точке.
  3. Сделайте небольшой шаг к наклону $\theta_j := \theta_j - \lambda * \frac{\partial}{\partial \theta_j} * J(\theta)$.
  4. Повторяем шаги 2-3, пока не сойдемся.

Теперь условие сходимости зависит от реализации алгоритма. Мы можем остановиться после 50 шагов, после какого-то порога или чего-то еще.

 import math # Example of the simple gradient descent algorithm taken from Wikipedia cur_x = 2.5 # The algorithm starts at point x gamma = 0.005 # Step size multiplier precision = 0.00001 previous_step_size = cur_x df = lambda x: 2 * x * math.cos(x) # Remember the learning curve and plot it while previous_step_size > precision: prev_x = cur_x cur_x += -gamma * df(prev_x) previous_step_size = abs(cur_x - prev_x) print("The local minimum occurs at %f" % cur_x)

The local minimum occurs at 4.712194

Мы не будем реализовывать эти алгоритмы в этой статье. Вместо этого мы будем использовать широко распространенную библиотеку машинного обучения Python с открытым исходным кодом scikit-learn . Он предоставляет множество очень полезных API для различных задач интеллектуального анализа данных и машинного обучения.

 from sklearn.linear_model import LinearRegression # LinearRegression uses the gradient descent method # Our data X = dataset[['Age']] y = dataset[['Pressure']] regr = LinearRegression() regr.fit(X, y) # Plot outputs plt.xlabel('Age') plt.ylabel('Blood pressure') plt.scatter(X, y, color='black') plt.plot(X, regr.predict(X), color='blue') plt.show() plt.gcf().clear() 

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

<matplotlib.figure.Figure at 0x120fae1d0>

 print( 'Predicted blood pressure at 25 yo = ', regr.predict(25) ) print( 'Predicted blood pressure at 45 yo = ', regr.predict(45) ) print( 'Predicted blood pressure at 27 yo = ', regr.predict(27) ) print( 'Predicted blood pressure at 34.5 yo = ', regr.predict(34.5) ) print( 'Predicted blood pressure at 78 yo = ', regr.predict(78) )
 Predicted blood pressure at 25 yo = [[ 122.98647692]] Predicted blood pressure at 45 yo = [[ 142.40388395]] Predicted blood pressure at 27 yo = [[ 124.92821763]] Predicted blood pressure at 34.5 yo = [[ 132.20974526]] Predicted blood pressure at 78 yo = [[ 174.44260555]]

Типы статистических данных

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

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

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

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

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

Логистическая регрессия

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

  • Это собака или кошка?
  • Эта опухоль злокачественная или доброкачественная?
  • Это вино хорошее или плохое?
  • Это спам по электронной почте или нет?

Или даже:

  • Какой номер на картинке?
  • К какой категории относится это письмо?

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

Прежде всего, мы можем повторно использовать ту же линейную гипотезу $h_\theta(x) = \theta^TX$ (в векторизованной форме). В то время как линейная регрессия может выводить любое число в интервале $[a, b]$, логистическая регрессия может выводить только значения в $[−1, 1]$, что является вероятностью попадания объекта в данную категорию или нет.

Используя сигмовидную функцию , мы можем преобразовать любое числовое значение в представление значения на интервале $[−1, 1]$.

\[f(x) = \frac{1}{1 + e^x}\]

Теперь вместо $x$ нам нужно передать существующую гипотезу и поэтому мы получим:

\[f(x) = \frac{1}{1 + e^{\theta_0 + \theta_1 * x_1 + ... + \theta_n * x_n}}\]

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

\[h_\theta(x) = \begin{case} 1 & \mbox{if } \theta^TX > 0 \\ 0 & \mbox{else} \end{cases}\]

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

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

В алгоритмах машинного обучения термин « наземная истина » относится к точности классификации обучающего набора для методов обучения с учителем.

Наш набор данных завершен, а это означает, что недостающих функций нет; однако у некоторых функций вместо категории стоит «*», что означает, что эта функция не имеет значения. Заменим все такие звездочки на нули.

 from sklearn.linear_model import LogisticRegression # Data data_path = os.path.join(os.getcwd(), "data/shuttle-landing-control.csv") dataset = read_csv(data_path, header=None, names=['Auto', 'Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility'], na_values='*').fillna(0) # Prepare features X = dataset[['Stability', 'Error', 'Sign', 'Wind', 'Magnitude', 'Visibility']] y = dataset[['Auto']].values.reshape(1, -1)[0] model = LogisticRegression() model.fit(X, y) # For now, we're missing one important concept. We don't know how well our model # works, and because of that, we cannot really improve the performance of our hypothesis. # There are a lot of useful metrics, but for now, we will validate how well # our algorithm performs on the dataset it learned from. "Score of our model is %2.2f%%" % (model.score(X, y) * 100)

Score of our model is 73.33%

Проверка?

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

 from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures from sklearn.linear_model import LinearRegression from sklearn.model_selection import cross_val_score # Ground truth function ground_truth = lambda X: np.cos(15 + np.pi * X) # Generate random observations around the ground truth function n_samples = 15 degrees = [1, 4, 30] X = np.linspace(-1, 1, n_samples) y = ground_truth(X) + np.random.randn(n_samples) * 0.1 plt.figure(figsize=(14, 5)) models = {} # Plot all machine learning algorithm models for idx, degree in enumerate(degrees): ax = plt.subplot(1, len(degrees), idx + 1) plt.setp(ax, xticks=(), yticks=()) # Define the model polynomial_features = PolynomialFeatures(degree=degree) model = make_pipeline(polynomial_features, LinearRegression()) models[degree] = model # Train the model model.fit(X[:, np.newaxis], y) # Evaluate the model using cross-validation scores = cross_val_score(model, X[:, np.newaxis], y) X_test = X plt.plot(X_test, model.predict(X_test[:, np.newaxis]), label="Model") plt.scatter(X, y, edgecolor='b', s=20, label="Observations") plt.xlabel("x") plt.ylabel("y") plt.ylim((-2, 2)) plt.title("Degree {}\nMSE = {:.2e}".format( degree, -scores.mean())) plt.show() 

Те же данные, смоделированные полиномами первой, четвертой и 30-й степеней, для демонстрации недообучения и переобучения.

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

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

Наш набор данных состоит из одной функции и его легко построить в 2D-пространстве; однако в реальной жизни у нас могут быть наборы данных с сотнями признаков, что делает невозможным их визуальное построение в евклидовом пространстве. Какие другие варианты у нас есть, чтобы увидеть, является ли модель недообучаемой или переоснащенной?

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

В учебных материалах вы обычно видите графики, подобные этим:

Теоретические вариации кривой обучения на основе полиномиальной степени.

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

 from sklearn.model_selection import learning_curve, ShuffleSplit # Plot learning curves plt.figure(figsize=(20, 5)) for idx, degree in enumerate(models): ax = plt.subplot(1, len(degrees), idx + 1) plt.title("Degree {}".format(degree)) plt.grid() plt.xlabel("Training examples") plt.ylabel("Score") train_sizes = np.linspace(.6, 1.0, 6) # Cross-validation with 100 iterations to get a smoother mean test and training # score curves, each time with 20% of the data randomly selected as a validation set. cv = ShuffleSplit(n_splits=100, test_size=0.2, random_state=0) model = models[degree] train_sizes, train_scores, test_scores = learning_curve( model, X[:, np.newaxis], y, cv=cv, train_sizes=train_sizes, n_jobs=4) train_scores_mean = np.mean(train_scores, axis=1) test_scores_mean = np.mean(test_scores, axis=1) plt.plot(train_sizes, train_scores_mean, 'o-', color="r", label="Training score") plt.plot(train_sizes, test_scores_mean, 'o-', color="g", label="Test score") plt.legend(loc = "best") plt.show() 

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

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

На «нормальном» графике скорости обучения в середине вы можете увидеть, как сходятся линии оценки обучения и оценки теста.

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


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

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

Перекрестная проверка

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

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

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

Сетка, демонстрирующая положение складок удержания в k-кратной перекрестной проверке.

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

Существует гораздо больше методов перекрестной проверки, таких как пропуск P , расслоение $k$-fold , перемешивание и разделение и т. д., но они выходят за рамки этой статьи.

Регуляризация

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

График, сопоставляющий исходную функцию и ее регуляризованный аналог.

Существует три основных метода регуляризации: Лассо, Тихонов и эластичная сетка.

Регуляризация L1 (или регуляризация Лассо ) выберет некоторые функции для сокращения до нуля, так что они не будут играть никакой роли в окончательной модели. L1 можно рассматривать как метод выбора важных функций.

L2-регуляризация (или регуляризация по Тихонову ) заставит все функции быть относительно небольшими, чтобы они оказывали меньшее влияние на модель.

Эластичная сеть представляет собой комбинацию L1 и L2.

Нормализация (масштабирование функций)

Масштабирование признаков также является важным шагом при предварительной обработке данных. В нашем наборе данных могут быть признаки со значениями $[-\infty, \infty]$ и другие признаки с другим масштабом. Это метод стандартизации диапазонов независимых значений.

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

Опорные векторные машины

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

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

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

График, показывающий гиперплоскость с полями.

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

Нейронные сети

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

Иллюстрация нейронной сети, показывающая различные входные данные, сопоставленные с временными значениями, которые, в свою очередь, сопоставляются с одним выходом.

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

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

Печально известный Титаник

RMS Titanic — британский пассажирский лайнер, затонувший в северной части Атлантического океана 15 апреля 1912 года после столкновения с айсбергом. Было около 2224 членов экипажа и пассажиров, и более 1500 человек погибли, что сделало это одно из самых смертоносных морских бедствий всех времен.

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

Наш набор данных будет заимствован с платформы соревнований по науке о данных Kaggle.

 import os from pandas import read_csv, concat # Load data data_path = os.path.join(os.getcwd(), "data/titanic.csv") dataset = read_csv(data_path, skipinitialspace=True) dataset.head(5)
идентификатор пассажира Выжил Pкласс Имя Секс Возраст СибСп парч Проездной билет Плата за проезд Салон самолета Отправился
0 1 0 3 Браунд, мистер Оуэн Харрис мужчина 22,0 1 0 А/5 21171 7.2500 NaN С
1 2 1 1 Камингс, миссис Джон Брэдли (Флоренс Бриггс... женский 38,0 1 0 ПК 17599 71,2833 С85 С
2 3 1 3 Хейккинен, мисс Лайна женский 26,0 0 0 СТОН/O2. 3101282 7,9250 NaN С
3 4 1 1 Футрелл, миссис Жак Хит (Лили Мэй Пил) женский 35,0 1 0 113803 53.1000 С123 С
4 5 0 3 Аллен, мистер Уильям Генри мужчина 35,0 0 0 373450 8.0500 NaN С

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

  • PassageId – идентификатор пассажира на борту
  • выживание - выжил ли человек в аварии
  • pclass – класс билета, например, 1-й, 2-й, 3-й
  • пол — Пол пассажира: Мужской или женский
  • имя - название включено
  • возраст – возраст в годах
  • sibsp — количество братьев и сестер/супругов на борту «Титаника».
  • parch – Количество родителей/детей на борту Титаника.
  • билет – номер билета
  • тариф - Пассажирский тариф
  • каюта – номер каюты
  • embarked – Порт посадки

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

 import pandas as pd # We need to drop some insignificant features and map the others. # Ticket number and fare should not contribute much to the performance of our models. # Name feature has titles (eg, Mr., Miss, Doctor) included. # Gender is definitely important. # Port of embarkation may contribute some value. # Using port of embarkation may sound counter-intuitive; however, there may # be a higher survival rate for passengers who boarded in the same port. dataset['Title'] = dataset.Name.str.extract(' ([A-Za-z]+)\.', expand=False) dataset = dataset.drop(['PassengerId', 'Ticket', 'Cabin', 'Name'], axis=1) pd.crosstab(dataset['Title'], dataset['Sex'])
Title \ Sex женский мужчина
Capt 0 1
Кол 0 2
Графиня 1 0
Дон 0 1
доктор 1 6
Jonkheer 0 1
Леди 1 0
Главный 0 2
Владелец 0 40
Мисс 182 0
Mlle 2 0
Mme 1 0
г-н 0 517
Миссис 125 0
РС 1 0
Преподобный 0 6
сэр 0 1
 # We will replace many titles with a more common name, English equivalent, # or reclassification dataset['Title'] = dataset['Title'].replace(['Lady', 'Countess','Capt', 'Col',\ 'Don', 'Dr', 'Major', 'Rev', 'Sir', 'Jonkheer', 'Dona'], 'Other') dataset['Title'] = dataset['Title'].replace('Mlle', 'Miss') dataset['Title'] = dataset['Title'].replace('Ms', 'Miss') dataset['Title'] = dataset['Title'].replace('Mme', 'Mrs') dataset[['Title', 'Survived']].groupby(['Title'], as_index=False).mean()
Заголовок Survived
0 Владелец 0.575000
1 Мисс 0.702703
2 г-н 0.156673
3 Миссис 0.793651
4 Другой 0.347826
 # Now we will map alphanumerical categories to numbers title_mapping = { 'Mr': 1, 'Miss': 2, 'Mrs': 3, 'Master': 4, 'Other': 5 } gender_mapping = { 'female': 1, 'male': 0 } port_mapping = { 'S': 0, 'C': 1, 'Q': 2 } # Map title dataset['Title'] = dataset['Title'].map(title_mapping).astype(int) # Map gender dataset['Sex'] = dataset['Sex'].map(gender_mapping).astype(int) # Map port freq_port = dataset.Embarked.dropna().mode()[0] dataset['Embarked'] = dataset['Embarked'].fillna(freq_port) dataset['Embarked'] = dataset['Embarked'].map(port_mapping).astype(int) # Fix missing age values dataset['Age'] = dataset['Age'].fillna(dataset['Age'].dropna().median()) dataset.head()
Survived Pclass Секс Возраст SibSp Parch Fare Embarked Заголовок
0 0 3 0 22,0 1 0 7.2500 0 1
1 1 1 1 38.0 1 0 71.2833 1 3
2 1 3 1 26,0 0 0 7.9250 0 2
3 1 1 1 35.0 1 0 53.1000 0 3
4 0 3 0 35.0 0 0 8.0500 0 1

At this point, we will rank different types of machine learning algorithms in Python by using scikit-learn to create a set of different models. It will then be easy to see which one performs the best.

  • Logistic regression with varying numbers of polynomials
  • Support vector machine with a linear kernel
  • Support vector machine with a polynomial kernel
  • Neural network

For every single model, we will use $k$-fold validation.

 from sklearn.model_selection import KFold, train_test_split from sklearn.pipeline import make_pipeline from sklearn.preprocessing import PolynomialFeatures, StandardScaler from sklearn.neural_network import MLPClassifier from sklearn.svm import SVC # Prepare the data X = dataset.drop(['Survived'], axis = 1).values y = dataset[['Survived']].values X = StandardScaler().fit_transform(X) X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state = None) # Prepare cross-validation (cv) cv = KFold(n_splits = 5, random_state = None) # Performance p_score = lambda model, score: print('Performance of the %s model is %0.2f%%' % (model, score * 100)) # Classifiers names = [ "Logistic Regression", "Logistic Regression with Polynomial Hypotheses", "Linear SVM", "RBF SVM", "Neural Net", ] classifiers = [ LogisticRegression(), make_pipeline(PolynomialFeatures(3), LogisticRegression()), SVC(kernel="linear", C=0.025), SVC(gamma=2, C=1), MLPClassifier(alpha=1), ]
 # iterate over classifiers models = [] trained_classifiers = [] for name, clf in zip(names, classifiers): scores = [] for train_indices, test_indices in cv.split(X): clf.fit(X[train_indices], y[train_indices].ravel()) scores.append( clf.score(X_test, y_test.ravel()) ) min_score = min(scores) max_score = max(scores) avg_score = sum(scores) / len(scores) trained_classifiers.append(clf) models.append((name, min_score, max_score, avg_score)) fin_models = pd.DataFrame(models, columns = ['Name', 'Min Score', 'Max Score', 'Mean Score'])
 fin_models.sort_values(['Mean Score']).head()
Имя Min Score Max Score Mean Score
2 Linear SVM 0.793296 0.821229 0.803352
0 Logistic Regression 0.826816 0.860335 0.846927
4 Нейронная сеть 0.826816 0.860335 0.849162
1 Logistic Regression with Polynomial Hypotheses 0.854749 0.882682 0.869274
3 RBF SVM 0.843575 0.888268 0.869274

Ok, so our experimental research says that the SVM classifier with a radial basis function (RBF) kernel performs the best. Now, we can serialize our model and re-use it in production applications.

 import pickle svm_model = trained_classifiers[3] data_path = os.path.join(os.getcwd(), "best-titanic-model.pkl") pickle.dump(svm_model, open(data_path, 'wb'))

Machine learning is not complicated, but it's a very broad field of study, and it requires knowledge of math and statistics in order to grasp all of its concepts.

Right now, machine learning and deep learning are among the hottest topics of discussion in Silicon Valley, and are the bread and butter of almost every data science company, mainly because they can automate many repetitive tasks including speech recognition, driving vehicles, financial trading, caring for patients, cooking, marketing, and so on.

Now you can take this knowledge and solve challenges on Kaggle.

This was a very brief introduction to supervised machine learning algorithms. Luckily, there are a lot of online courses and information about machine learning algorithms. I personally would recommend starting with Andrew Ng's course on Coursera.

Ресурсы

  • Andrew Ng's course on Coursera
  • Kaggle datasets
  • A deep learning reading list
  • A list of free books on machine learning algorithms, data mining, deep learning, and related topics
  • Введение в теорию машинного обучения и ее приложения: наглядное пособие с примерами
Related: Machines and Trust: How to Mitigate AI Bias