Если вы новичок в области статистики (как и я), следующая статья может быть вам интересна. Почему? Потому что он дает обзор базовой техники машинного обучения, описанной в каждой статистической книге для начинающих, которую вы можете там найти. Речь идет о простой линейной регрессии и о том, как ее реализовать с помощью Python. Я посвятил некоторое время изучению этой темы, а теперь хочу поделиться с вами некоторыми мыслями.

Чего можно ожидать:

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

  1. Я буду визуализировать и оценивать некоторые данные, представляющие основы для создания регрессионной модели. Эти данные содержат информацию о местах и ​​отметках времени запуска приложений в определенном месте.
  2. Будет представлен один подход (градиентный спуск) для поиска параметров (также называемых весами) модели простой линейной регрессии, которая может прогнозировать количество открытий приложений для определенного час.
  3. Я буду сравнивать свою реализацию с известной библиотекой (scikit learn)

К вашему сведению: я использовал Jupyter Notebook для визуализации данных и реализации регрессионной модели на Python. Из него я собрал следующие рисунки, сюжеты и отрывки.

Данные

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

Данные содержат отметки времени процедур запуска определенного приложения, открытого в определенном месте.

Это выглядит так:

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

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

Первое, что я сделал, - это преобразовал временные метки в кодировке ISO в представление даты на языке Python. Это можно сделать с помощью:

import dateutil.parser
## convert the timestamp to a python date object 
data['timestamp'] = 
    list(map(dateutil.parser.parse, data['timestamp']))

После этого я добавил в набор данных столбцы час и день.

## add dedicated columns for day, hour and weekday 
data['hour'] = list(map(lambda v : v.hour, data['timestamp']))
data['day'] = list(map(lambda v : v.day, data['timestamp']))

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

Если вы теперь внимательно посмотрите на график, показанный выше, уже заметны три вещи:

1. Существует тенденция, что пользователи открывают приложение ближе к вечеру.

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

3. Количество открытий приложений увеличивается в течение дня и снова уменьшается после просмотра в 3/4/5 вечера. Кажется, что простая линейная модель не подходит для моего случая использования из-за ее ограниченной сложности.

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

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

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

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

Чтобы избавиться от экстремальных значений, вы можете использовать, например, Межквартильный диапазон (IQR) ( https://en.wikipedia.org/wiki/Interquartile_range ) для расчета верхний и нижний упоры. Все значения, находящиеся ниже или выше этих ограждений, считаются выбросами и удаляются из набора данных. Реализация довольно проста с использованием numpy. Сначала вам нужно получить первый и третий квартили. IQR - это разница между этими двумя. Нижний и верхний забор можно рассчитать следующим образом:

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

Модель простой линейной регрессии

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

Мы создадим модель линейной регрессии, выполнив контролируемое обучение. На основе имеющихся у нас данных («руководитель») мы пытаемся найти гипотезу h (линейная функция с параметрами 𝛉_0 и 𝛉_1), который сопоставляет вход (в данном случае конкретный час) с выходным или целевым значением (количеством открытий приложения) с учетом его веса 𝛉 (тета). Формулу можно представить следующим образом:

с x_0 = 1 (и поэтому удален из формулы выше).

Наша цель - найти гипотезу h, которая наилучшим образом соответствует нашим данным. Что означает «лучше всего соответствует данным»? Это означает найти значения для 𝛉 гипотезы h для того, чтобы как можно точнее оценить количество открытий приложений за данный час. Разница между нашим расчетным значением, основанным на h и реальным решением y, должна быть как можно меньше.

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

Что мы делаем здесь, так это вычисляем квадрат разницы между прогнозируемым значением, заданным нашей гипотезой h (x), и целевым значением y с учетом конкретных входных данных. В результате мы получаем затраты для конкретной гипотезы h с учетом ее веса 𝛉. Накопив полный набор данных, используемый для обучения, мы получаем значение, которое определяет, насколько хороша или плоха гипотеза h для данных.

Кстати о обучении: прежде чем мы продолжим, нам нужно уточнить термины обучающий набор и набор тестов. В области машинного обучения принято разделять полный набор данных на (часто разрозненные) разделы разного размера и для разных целей. Чтобы узнать веса модели, мы используем специальный обучающий набор. Он должен содержать самый большой блок данных, чтобы получить как можно больше информации о базовой совокупности. Чтобы оценить нашу модель в конце, мы используем другой полностью разобщенный набор данных, test set.

Напомним: наша общая цель - найти линейную модель, в которой затраты были бы как можно меньше (мы стараемся минимизировать J (𝛉)). Один из подходов состоит в том, чтобы многократно изменять параметры 𝛉, пока мы не сходимся к значению 𝛉, которое минимизирует J (𝛉). Точнее, мы можем использовать подход градиентного спуска. Теперь я мог бы подчинить вас математическим основам, но мы пропустим эту часть и сосредоточимся непосредственно на правиле обновления для одного обучающего примера. Он представлен

(Это правило также известно как правило обучения Уидроу-Хоффа. Для получения дополнительной информации см. H ttps: //blog.oureducation.in/learning-rule/)

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

Прежде чем я представлю свою реализацию, давайте суммируем то, что описано в правиле обучения Widrow-Hoff: для каждого обучающего примера i мы обновляем наши веса j в отношении разницы между нашим прогнозом и реальным значением, умноженным на скорость обучения 𝞪 и текущее входное значение. Не так уж и сложно, правда? Итак, давайте код.

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

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

Выше вы видите реализацию подхода стохастического градиентного спуска. Для каждого примера обучения мы обновляем наши веса в соответствии с правилом обучения Уидроу-Хоффа, описанным выше. Мы делаем это 10000 раз для нашей обучающей выборки со скоростью обучения 0,00001. Наш результат сходится к линейной функции с весами, заданными как 𝛉_0 = 54,57221825 и 𝛉_1 = 2,67104843. Изменение стоимости показано следующим образом:

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

Оценка

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

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

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

Представьте себе другой сценарий, в котором вы имеете дело с дискретным целевым пространством: на основе данных с атрибутами разных людей (например, вес, рост, размеры бедер или плеч) вы хотите оценить размер их одежды (S, M, L и т. Д.) Ваши данные содержат разные значения атрибутов для каждого человека и итоговый размер одежды. Ваша задача - оценить размер одежды нового человека с учетом различных параметров его тела. Проблема классификации.

Вы можете легко оценить полученную модель описанного сценария, используя набор тестов и несколько простых показателей. Вы можете подсчитать, насколько часто прогноз модели является правильным и может получить процентное значение (точность и напоминание, хорошее описание можно найти здесь https: // todatascience .com / precision-vs-repl-386cf9f89488 ), который представляет собой меру качества вашей модели. Однако это невозможно для проблемы регрессии, когда вы имеете дело с непрерывным целевым пространством. Нужен другой подход.

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

Чтобы создать модель линейной регрессии с помощью scikit-learn, вам нужно вызвать конструктор LinearRegression (насколько подходит) и можно обучить модель с помощью model.fit. Чтобы оценить целевое значение для заданного входа, мы используем model.predict. Таким образом, код довольно прост:

После тренировки я визуализировал результаты для набора тестов:

Красная линия представляет прогнозы, сделанные scikit learn. Зеленая линия основана на предсказаниях нашей модели. Очень похоже, не так ли? Похоже, у нас все получилось. Но какая из представленных моделей подходит лучше всего? Все решения, которые можно было принять на основе представленной выше визуализации, слишком неточны. Нам нужен лучший подход к оценке.

На помощь приходит статистика R-квадрата

Стандартным показателем согласия для моделей линейной регрессии является статистика R-квадрат. Как заявили Агнес Оги и др. al это процент вариации переменной ответа, который объясняется линейной моделью. Другими словами, статистика R-квадрата представляет собой долю дисперсии, охватываемую нашей линейной моделью, по сравнению с общей дисперсией в данных. Значение 1 означает, что все покрыто, 0 означает, что наша модель не может объяснить никаких вариаций.

К счастью, scikit learn уже предоставляет метрику R-квадрат. Результаты показаны ниже.

Мы можем изучить две вещи:

  1. Наши значения R-квадрата в целом очень малы.
  2. Значение R-квадрата нашей линейной модели немного меньше, чем у модели scikit .

Что это значит? Что подхода в целом недостаточно, чтобы охватить концепцию целевого пространства? Что наша модель подходит немного хуже, чем модель из scikit learn? Да и да.

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

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

  1. Отсутствующие переменные в вашей модели
  2. Отсутствует член более высокого порядка переменной в модели для объяснения кривизны, или
  3. Отсутствует взаимодействие между терминами, уже присутствующими в модели.

(ссылка на http://blog.minitab.com/blog/adventures-in-statistics-2/why-you-need-to-check-your-residual-plots-for-regression-analysis)

И мы умеем это делать. С большой вероятностью можно ожидать, что в 17:00 остаток будет отрицательным. Это плохо. Мы должны перейти на модель нелинейной регрессии! (В следующий раз)

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

Заключение

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

Эта статья первая в своем роде. Это первая из серии статей, посвященных моделям машинного обучения, и первая средняя статья для меня в целом. Я надеюсь, что это поможет вам лучше понять общую тему. Для меня это действительно сработало. Жду ваших отзывов :)