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

В этом посте мы исследуем саму модель.

Исследование данных

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

Основная информация, какие-либо отсутствующие данные?

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

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

Проверьте различия по сравнению с прошлым годом

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

В нашем случае у нас есть данные за ~ 2 года за 3 календарных года (август 2018 г. - апрель 2020 г.). Разделив фрейм данных на 3 dfs, мы можем проверить, насколько по-разному выглядит каждый месяц и / или неделя по годам. Я стараюсь изучать сходства и тенденции с помощью линейных диаграмм. Я хотел бы подробнее сравнить данные о продажах в прошлом году, но это тема, которая может использовать отдельный пост или серию постов.

См. динамику продаж за ~ 2 года ниже

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

Этот график говорит нам о том, что с августа 2018 года наблюдается устойчивый рост продаж. В первый год, июль, также наблюдается слабый месяц. Кроме того, что-то изменилось в 2020 году, поскольку мы видим, что продажи постоянно падают до нуля. Мы знаем, что изменение заключается в том, что магазин закрывается 2 дня в неделю. Важно помнить об этом, поскольку при построении нашей модели прогнозирования даты с нулевыми продажами будут влиять на прогнозы модели.

Бонусное чтение - эта часть не используется в модели, но ее стоит изучить.

Создайте переменную MOM

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

Я решил провести повторную выборку данных и сгруппировать продажи за каждый месяц, суммируя их. Для этого в Python вы можете использовать функцию Pandas.df.resample (« M ). Sum ()». Вам необходимо убедиться, что переменная даты становится вашим индексом и что данные переменной имеют формат даты. Помните, в начале, когда мы проверяли основную информацию нашего df (df.info ()), и Date Dtype был object? Вы должны преобразовать его в дату Dtype с помощью функции pandas.to_datetime (). Если тип данных не дата, вы не сможете использовать функцию передискретизации.

Как только вы это сделаете, вы можете создать новую переменную под названием «мама», которая будет содержать разницу между каждым месяцем. Для этого мы используем функцию df.sales.diff (), как показано ниже.

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

Процентное изменение MOM

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

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

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

Конец бонусного раздела

Создание независимых переменных

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

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

Название этого раздела - «Создание независимых переменных» - слово создание используется здесь буквально. Наблюдая за изменениями на местном рынке, мы могли определить, сколько ресторанов было открыто с начала деятельности AINA до 19 апреля 2020 года. Для представления открытых ресторанов мы используем значение 1, а для закрытых ресторанов значение 0. Это значение равно 0. простое двоичное кодирование, см. например снимок экрана:

То, что вы видите выше, просто показывает, что с 2019–02–23 по 2019–03–15 было 12 действующих ресторанов на Deliveroo и 35 на JustEat в Стерлинге. Еще одна проблема, связанная с моделью, заключается в том, что она не знает исключений, таких как рождественские и пасхальные праздники.

Чтобы помочь модели с исключениями, нам нужно снабдить ее такими же двоичными данными, как и для количества открытых ресторанов на разные даты. Это легко сделать с помощью пары строк кода Python, и вы можете увидеть пример результата выше (ch_18 - это Рождество 2018 года, ea_18 - это Пасха 2018 года и т. Д.).

Наконец, наша модель должна быть осведомлена об изменениях рабочих дат AINA, помните, что в 2020 году даты с продажами до 0 - это два дня в неделю, когда магазин закрыт. Как и все остальное, мы создаем двоичную переменную с именем «aina_closed».

Теперь к модели

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

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

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

Цель модели

Прежде чем строить нашу модель, нам нужно вспомнить, какова цель.

Цель модели:

Для прогнозирования продаж на следующие 2–3 недели в неделю на уровне ежедневной детализации на основе факторов того, сколько ресторанов открыто в данный день в городе Стерлинг во время правил социального дистанцирования пандемии коронавируса.

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

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

Машинное обучение с учителем

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

Временной ряд - это набор объектов данных, индексированных во временном порядке.

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

Подробнее об этой теме и о том, как преобразовать данные, читайте в этом сообщении:

Для данных, с которыми мы работаем, я использовал следующий код:

df1 = df.copy()
num_lags = 7 # number of lags and windows lengths for mean aggregation (1 lag = 1 day since our data is daily)
delay = 1 # predict target one step ahead (number of observations as output)
for column in df1:
  for lag in range(1, num_lags+1):
     df1[column + ‘_lag’ + str(lag)] = df1[column].shift(lag*-1-     (delay-1))
     df1[column + ‘_avg_window_length’ + str(lag+1)] =    df1[column].shift(-1-(delay-1)).rolling(window=lag+1, center=False).mean().shift(1-(lag+1))
df1.dropna(inplace=True)
mask = (df1.columns.str.contains(‘all_sales’) | df1.columns.str.contains(‘lag’) | df1.columns.str.contains(‘window’))
df1_processed = df1[df1.columns[mask]]
# the columns in the processed dataframe
df1_processed.columns

Понимание логики приведенного выше кода

По сути, в традиционной терминологии прогнозирования временных рядов текущее время (t) и будущее время (t + 1, t + n) - это время прогноза, а прошлые наблюдения (t-1, t-n) используются для составления прогнозов. Таким же образом мы используем положительные и отрицательные сдвиги pandas.DataFrame.shift () для создания нового DataFrame из временного ряда с последовательностями шаблонов ввода и вывода для задачи контролируемого обучения.

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

Разделение данных поезда и теста

В моделях данных мы склонны разделять наборы данных 80/20 для обучения / тестирования. Мы разделяем данные, чтобы можно было обучить модель на большинстве данных (80%) и проверить, насколько хорошо она работает с новыми данными на оставшихся 20%.

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

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

Модель H2O AutoML

У H2O есть хорошая документация, если вы хотите попробовать. Как правило, вы начинаете с выполнения команды init для инициализации движка H2O:

h2o.init(nthreands=-1)

H2O DataFrames отличаются от фреймов pandas, поэтому нам нужно преобразовать наши DataFrames из pandas в h2o:

hf1_train = h2o.H2OFrame(df1_train)
hf1_test = h2o.H2OFrame(df1_test)

Затем нам нужно выбрать характеристики для модели:

y = 'all_sales'
X = hf1_train.columns
X.remove(y)

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

Запустить AutoML

Это та часть, которая всех волнует, пора запустить нашу модель.

aml1 = H2OAutoML(max_runtime_secs = 600, seed = 42)
aml1.train(x = X, y = y, training_frame = hf1_train,    leaderboard_frame = hf1_test)

Мы определяем leaderboard_frame как hf1_test (тестовые данные, которые мы создали ранее, когда делали разделение 90/10). Если мы не определяем leaderboard_frame, согласно документации h2o, таблица лидеров будет использовать метрики перекрестной проверки, или если перекрестная проверка отключена параметром nfolds = 0, тогда кадр таблицы лидеров будет автоматически сгенерирован из кадра обучения . Рейтинг в таблице лидеров используется для ранжирования моделей в зависимости от того, насколько хорошо модели работают с вашими данными. Я предлагаю вам выбрать данные тестирования, поскольку они обеспечивают больший контроль, а 100% -ная уверенность в алгоритме H2O может затруднить понимание результатов вашей модели.

Проверить таблицу лидеров

Как только AutoML будет запущен, мы можем проверить нашу таблицу лидеров, чтобы увидеть, какие модели работают лучше всего:

lb1 = aml1.leaderboard
lb1

Наша таблица лидеров показывает, что самые эффективные модели - это модели GLM_1_AutoML и XGBoost.

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

leader_model1 = aml1.leader
leader_model1

Таким образом, мы видим, что среднеквадратичная ошибка (RMSE) для данных обучения составляет ~ 72%, а при перекрестной проверке ~ 76%. Точно так же у нас есть высокая среднеквадратическая ошибка журнала (RMSLE) с ~ 0,80 для данных поезда и ~ 0,84 для перекрестной проверки. Оба показывают, насколько близки наблюдаемые точки данных к прогнозируемым значениям, чем выше число, тем больше несходство (воспринимайте это как стандартное отклонение; насколько члены группы отличаются от среднего значения группы). Основное отличие состоит в том, что RMSLE более надежен при обработке выбросов в данных. RMSE, вероятно, увеличит значение ошибки до очень высокого значения при столкновении с выбросами, в то время как RMSLE уменьшает выбросы, сводя на нет их эффекты.

Лучшее значение для моделей прогнозирования, подобных этой, как правило, представляет собой R-квадрат (R²). Это просто и интуитивно понятно. R² масштабируется от 0 до 1, и чем ближе значение к 1, тем больше вероятность того, что прогноз вашей модели будет близок к реальности (это приблизительное определение для целей этого сообщения, и я бы рекомендовал вам прочитать и понять статистические показатели дальше). R² нашей модели составляет ~ 0,58 в наборе обучающих данных и ~ 0,54 в данных перекрестной проверки.

Рекомендую прочитать дальше:

Фактические прогнозы модели

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

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

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

Заключительные мысли

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

Могут ли модели ML или DL работать во времена, подобные пандемии Covid-19 2020 года?

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

Способ справиться с двумя закрытыми днями - вместо этого запускать модель на недельном уровне (см. Раздел о бонусах в середине сообщения, чтобы узнать, как это сделать).

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

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