Прогнозирование спроса с помощью машинного обучения

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

Необходимость прогнозирования спроса

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

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

Что мы будем прогнозировать?

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

Наш датасет представляет собой слияние нескольких csv файлов с данными, каждый из которых содержит себе разные строки и столбцы о состоянии отрасли общепита:

  • Информация о блюдах (meal_info.csv): Этот файл представляет собой кулинарную карту нашего набора данных. В нем содержится подробная информация о различных предлагаемых блюдах, сгруппированных по типу и кухне. Эта информация имеет ключевое значение для понимания потребительских предпочтений и тенденций в выборе блюд;
  • Информация о распределительных центрах доставки (fulfilment_center_info.csv): Как основа логистической сети, этот файл содержит подробную информацию о различных центрах, из которых отправляются блюда. Он включает данные о местоположении, типе и районе работы центра, что очень важно для понимания географического влияния на спрос;
  • Исторические данные (train.csv): Здесь мы погружаемся в прошлое, чтобы предсказать будущее. Исторические данные включают в себя еженедельные заказы, цены на кассе и базовые цены, а также информацию о том, рекламировалось ли блюдо по электронной почте или размещалось на главной странице сайта. Это богатая историческая справка о заказах потребителей, ценовых стратегиях и рекламных акциях;
  • Прогнозы на будущее (test.csv): Этот файл содержит аналогичную информацию, что и исторические данные, но используется для прогнозирования будущего спроса. Это тестовая площадка для наших моделей машинного обучения, где мы применяем наши идеи и теории.

Приступаем к реализации

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

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

df = pd.read_csv('mealsdata.csv')
mealinfo_df = pd.read_csv('meal_info.csv')
fulfillment_df = pd.read_csv('fulfilment_center_info.csv')

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

df.head()

Датафрейм с данными Pandas. Содержание датафрейма train_df

Рис. 1: Датафрейм с данными Pandas. Содержание датафрейма train_df

mealinfo_df.head()

Рис. 2: Содержание датафрейма mealinfo_df

fulfillment_df.head()

Рис. 3: Содержание датафрейма fulfillment_df

Прежде чем перейти к анализу данных, давайте объединим датафреймы train_df, fulfillment_info и mean_info.

df_merged = df.merge(fulfillment_df, on='center_id', how='left')
df_merged = df_merged.merge(mealinfo_df, on='meal_id', how='left')

Выборка нескольких строк после объединения.

df_merged.head()

Рис. 4: Содержание датафрейма df_merged

Переход к анализу данных

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

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

Как меняются еженедельные заказы с течением времени?

# Агрегируем данные о заказах по неделям
weekly_orders = df_merged.groupby('week')['num_orders'].sum()

plt.figure(figsize=(8, 5))
sns.lineplot(x=weekly_orders.index, y=weekly_orders.values)
plt.title('Weekly Orders Over Time')
plt.xlabel('Week')
plt.ylabel('Total Number of Orders')
plt.grid(True)
plt.show()

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

Рис. 5: График количества заказов по неделям

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

Какова зависимость между ценой заказа и количеством заказов?

# Создание диаграммы рассеяния для анализа связи между ценой на кассе и количеством заказов
plt.figure(figsize=(12, 6))
sns.scatterplot(x='checkout_price', y='num_orders', data=df_merged, alpha=0.5)
plt.title('Relationship Between Checkout Price and Number of Orders')
plt.xlabel('Checkout Price')
plt.ylabel('Number of Orders')
plt.grid(True)
plt.show()

Диаграмма рассеяния взаимосвязи между ценой на кассе и количеством заказов

Рис. 6: Диаграмма рассеяния взаимосвязи между ценой на кассе и количеством заказов

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

  1. Широкий диапазон цен: График показывает широкий диапазон цен на кассе, что свидетельствует о разнообразной стратегии ценообразования на различные блюда или услуги;
  2. Области высокой плотности: Есть области с высокой плотностью точек, особенно при более низких ценах и меньших объемах заказов, что говорит о том, что значительное количество транзакций включает в себя меньшее количество заказов по более низким ценам;
  3. Разрозненные области с высокими ценами: При более высоких ценах на кассу поступает меньше заказов, о чем свидетельствует малое количество точек в этих регионах;
  4. Нелинейная зависимость: Взаимосвязь между ценой и заказами не имеет четкой линейной тенденции, что говорит о том, что другие факторы, помимо цены, также играют важную роль в определении количества заказов.
Читайте также:  Прогнозирование временных рядов с помощью ARIMA, SARIMA, ARFIMA

Какие категории блюд пользуются наибольшей популярностью?

import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# Группировка данных и подсчет заказов по категориям
category_orders = df_merged.groupby('category')['num_orders'].sum().sort_values(ascending=False)

# Построение графика
plt.figure(figsize=(12, 6))
sns.barplot(x=category_orders.values, y=category_orders.index, palette="viridis")
plt.title('Total Orders by Meal Category')
plt.xlabel('Number of Orders')
plt.ylabel('Meal Category')
plt.grid(True)
plt.show()

Общее количество заказов блюд по категориям

Рис. 7: Общее количество заказов блюд по категориям

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

Как различаются недельные заказы в разных распредцентрах?

# Группировка данных по центрам и агрегация заказов
center_weekly_orders = df_merged.groupby('center_id')['num_orders'].sum().sort_values(ascending=False)

# Построение графика
plt.figure(figsize=(15, 8))
sns.barplot(x=center_weekly_orders.index, y=center_weekly_orders.values, palette="cubehelix")
plt.title('Total Weekly Orders Per Fulfillment Center')
plt.xlabel('Center ID')
plt.ylabel('Total Number of Orders')
plt.xticks(rotation=90)
plt.grid(True)
plt.show()

Количество еженедельных заказов на каждый распределительный центр

Рис. 8: Количество еженедельных заказов на каждый распределительный центр

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

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

Как различаются недельные заказы в разных кухнях?

# Агрегация данных по кухне и неделе
cuisine_weekly_orders = df_merged.groupby(['cuisine', 'week'])['num_orders'].sum().reset_index()

# Пивотирование данных
cuisine_weekly_orders_pivot = cuisine_weekly_orders.pivot(index='week', columns='cuisine', values='num_orders')

# Построение графика
plt.figure(figsize=(15, 8))
sns.lineplot(data=cuisine_weekly_orders_pivot, dashes=False)
plt.title('Weekly Orders per Cuisine')
plt.xlabel('Week')
plt.ylabel('Total Number of Orders')
plt.legend(title='Cuisine Type', bbox_to_anchor=(1.05, 1), loc='upper left')
plt.grid(True)
plt.show()

Динамика заказов по различным типам кухонь по неделям

Рис. 9: Динамика заказов по различным типам кухонь по неделям

# Группировка данных по неделе и кухне, подсчет заказов
weekly_orders = df_merged.groupby(['week', 'cuisine'])['num_orders'].sum().reset_index()

# Определение кухни с наибольшим средним количеством заказов
highest_orders_cuisine = weekly_orders.groupby('cuisine')['num_orders'].mean().idxmax()

# Извлечение данных о кухне с максимальным средним
highest_orders_data = weekly_orders[weekly_orders['cuisine'] == highest_orders_cuisine]

# Вывод результата
print("Кухня с наибольшим средним количеством заказов:", highest_orders_cuisine)
print(highest_orders_data.describe())

Определение кухни с наибольшим количеством заказов и ее метрик

Рис. 10: Определение кухни с наибольшим количеством заказов и ее метрик

Итальянская кухня стала самой заказываемой среди всех анализируемых кухонь, продемонстрировав заметный средний недельный объем заказов – около 304640. Однако такая популярность сопровождается значительной вариативностью, о чем свидетельствует стандартное отклонение еженедельных заказов, составляющее около 95519. Диапазон заказов блюд итальянской кухни довольно широк: от минимума в 126739 до максимума в 743949 за 145 недель, охватываемых набором данных.

Как меняются общие заказы в зависимости от сочетания типов кухни и категорий блюд?

# Группировка данных по кухне и категории, подсчет заказов
cuisine_category_orders = df_merged.groupby(['cuisine', 'category'])['num_orders'].sum().unstack()

# Построение тепловой карты
plt.figure(figsize=(17, 8))
sns.heatmap(cuisine_category_orders, annot=True, fmt=".0f", cmap="YlGnBu", linewidths=.5)
plt.title('Total Orders for Each Combination of Cuisine and Category')
plt.xlabel('Category')
plt.ylabel('Cuisine')   

plt.show()

Общее количество заказов блюд для каждой комбинации кухни и категории

Рис. 11: Общее количество заказов блюд для каждой комбинации кухни и категории

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

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

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

Как операционная площадь распредцентра влияет на количество заказов?


plt.figure(figsize=(12, 6))
sns.scatterplot(x='op_area', y='num_orders', data=center_orders_op_area)
plt.title('Relationship Between Operational Area and Number of Orders per Center')
plt.xlabel('Operational Area')
plt.ylabel('Total Number of Orders')
plt.grid(True)   
plt.show()

Взаимосвязь между площадью распределительного центра и количества заказов

Рис. 12: Взаимосвязь между площадью распределительного центра и количества заказов

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

  • Различные объемы заказов: Общий объем заказов в разных распредцентрах варьируется в широких пределах, о чем свидетельствует вертикальный разброс точек;
  • Различные операционные области: Горизонтальный разброс показывает, что центры имеют различные операционные области;
  • Сложная взаимосвязь: На графике не прослеживается четкой линейной зависимости между операционной зоной и общим количеством заказов. Некоторые центры с большими операционными зонами имеют большие объемы заказов, но это не является устойчивой тенденцией для всех распределительных центров;
  • Другие влияющие факторы: Хотя операционная зона может быть фактором, определяющим способность центра обрабатывать заказы, другие элементы, такие как местоположение, эффективность управления и спрос на местном рынке, также играют решающую роль в определении объема заказов.
Читайте также:  Анализ песен рейтинга Billboard Top-100 с 1958 по 2023 гг

Далее изучим влияние рекламных акций на количество заказов.

Влияет ли наличие промо-акций (рассылка по электронной почте или на главной странице сайта) на количество заказов?

# Агрегация данных по email-рассылкам и размещению на главной странице
emailer_orders = df_merged.groupby('emailer_for_promotion')['num_orders'].sum()
homepage_orders = df_merged.groupby('homepage_featured')['num_orders'].sum()   

# Создание подграфиков
fig, axes = plt.subplots(1, 2, figsize=(14, 6))

# Построение столбчатых диаграмм
sns.barplot(x=emailer_orders.index, y=emailer_orders.values, ax=axes[0])
axes[0].set_title('Impact of Emailer Promotion on Orders')
axes[0].set_xlabel('Emailer Promotion')
axes[0].set_ylabel('Number of Orders')   

sns.barplot(x=homepage_orders.index, y=homepage_orders.values, ax=axes[1])
axes[1].set_title('Impact of Homepage Featured on Orders')
axes[1].set_xlabel('Homepage Featured')
axes[1].set_ylabel('Number of Orders')   

# Настройка отображения графиков
plt.tight_layout()
plt.show()

График влияния рассылок и акций на количество заказов

Рис. 13: График влияния рассылок и акций на количество заказов

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

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

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

Итак, мы рассмотрели наши данные и увидели несколько интересных корреляций. Давайте теперь перейдем к следующему этапу – предварительной обработке данных.

Обнаружение и устранение выбросов

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

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

Начнем с обнаружения аномалий с помощью визуализации:

def detect_outliers_iqr(data, feature):
    Q1 = data[feature].quantile(0.25)
    Q3 = data[feature].quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    outliers = data[(data[feature] < lower_bound) | (data[feature] > upper_bound)]
    return outliers

numerical_cols = ['checkout_price', 'base_price']
outliers_train = {col: detect_outliers_iqr(df_merged, col) for col in numerical_cols}

plt.figure(figsize=(15, 5))
for i, col in enumerate(numerical_cols):
    plt.subplot(1, len(numerical_cols), i + 1)
    sns.boxplot(y=df_merged[col])
    plt.title(f'Box Plot of ({col})')

plt.tight_layout()
plt.show()

outliers_count = {col: len(outliers_train[col]) for col in numerical_cols}

Боксплоты разброса цен checkout_price и base_price

Рис. 14: Боксплоты разброса цен checkout_price и base_price

Точки на наших боксплот-графиках – это аномалии. Мы ограничим выбросы для столбцов checkout_price и base_price. Для этого нужно установить верхнюю или нижнюю границу выбросов, определяемую методом интерквартильного размаха (IQR).

def cap_outliers_iqr(data, feature):
    Q1 = data[feature].quantile(0.25)
    Q3 = data[feature].quantile(0.75)
    IQR = Q3 - Q1
    lower_bound = Q1 - 1.5 * IQR
    upper_bound = Q3 + 1.5 * IQR
    data[feature] = data[feature].clip(lower=lower_bound, upper=upper_bound)
    return data

df_merged = cap_outliers_iqr(df_merged, 'checkout_price')
df_merged = cap_outliers_iqr(df_merged, 'base_price')

plt.figure(figsize=(10, 4))
for i, col in enumerate(['checkout_price', 'base_price'], 1):
    plt.subplot(1, 2, i)
    sns.boxplot(y=df_merged[col])
    plt.title(f'Box Plot of {col} (Capped)')

plt.tight_layout()
plt.show()

Боксплоты разброса цен checkout_price и base_price, очищенные от аномальных значений

Рис. 15: Боксплоты разброса цен checkout_price и base_price, очищенные от аномальных значений

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

Категориальное кодирование (Categorical encoding)

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

categorical_cols = df_merged.select_dtypes(include=['object']).columns
print("Categorical columns:", categorical_cols)

Столбцы датафрейма df_merged с категорийным типом данных

Рис. 16: Столбцы датафрейма df_merged с категорийным типом данных

В нашем наборе данных мы выделили три категориальных столбца: ‘center_type’, ‘category’ и ‘cuisine’. Чтобы эффективно включить их в наши аналитические модели, мы применим к этим столбцам метод one-hot кодирования.

df_encoded = pd.get_dummies(df_merged, columns=categorical_cols)

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

pd.set_option('display.max_columns', None)  # This will display all columns
df_encoded.head()

Данные в датафрейме df_encoded после применения one-hot кодирования

Рис. 17: Данные в датафрейме df_encoded после применения one-hot кодирования

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

Читайте также:  Прогнозирование трафика и конверсий сайта с помощью Prophet

Например, если один из категориальных столбцов с именем category имел значение Soup для определенной строки, то в преобразованном датафрейме столбец category_Soup будет иметь значение 1 для этой строки, а все остальные столбцы, созданные на основе category (например, category_Sandwich, category_Salad), будут иметь значение 0 для этой строки.

Нормализация данных для машинного обучения

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

Нормализация – это метод масштабирования числовых признаков датафрейма таким образом, чтобы среднее значение было равно 0, а стандартное отклонение – 1. Этот процесс особенно важен при работе с признаками, которые различаются по величине, единицам измерения и диапазону.

Нормализацию еще часто называют масштабированием, поскольку мы приводим разброс всех переменных в датафрейме к единому масштабу. Как правило, нормализацию делают с помощью алгоритма StandardScaler из библиотеки scikit-learn.

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

from sklearn.preprocessing import StandardScaler

# Разделение на признаки и целевую переменную
X = df_encoded.drop('num_orders', axis=1)
y = df_encoded['num_orders']

# Нормализация признаков
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)

# Преобразование обратно в DataFrame
X_scaled = pd.DataFrame(X_scaled, columns=X.columns)

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

X_scaled.head()

Данные в датафрейме после нормализации

Рис. 18: Данные в датафрейме после нормализации

Построение моделей для прогнозирования спроса

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

В данном случае мы остановимся на трех популярных моделях машинного обучения:

  • Линейная регрессия;
  • Random Forest;
  • Decision Tree.

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

Шаг 1: Разделение данных

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

from sklearn.model_selection import train_test_split

# X_scaled содержит стандартизированные признаки, а y содержит целевую переменную 'num_orders'
X_train, X_test, y_train, y_test = train_test_split(X_scaled, y, test_size=0.2, random_state=42)

Шаг 2: Обучение моделей

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

  • Линейная регрессия: Эта модель часто является первым выбором для решения задач регрессии из-за своей простоты и интерпретируемости;
  • Случайный лес: Ансамблевая модель, известная своей высокой точностью и надежностью, которая работает путем построения нескольких деревьев решений;
  • Дерево решений: Модель, которая разбивает данные на ветви, образуя древовидную структуру. Она полезна своей интерпретируемостью, но может быть склонна к переобучению.
from sklearn.linear_model import LinearRegression
from sklearn.ensemble import RandomForestRegressor
from sklearn.tree import DecisionTreeRegressor

# Linear Regression
linear_model = LinearRegression()
linear_model.fit(X_train, y_train)
predictions_linear = linear_model.predict(X_test)

# Random Forest
rf_model = RandomForestRegressor()
rf_model.fit(X_train, y_train)
predictions_rf = rf_model.predict(X_test)

# Decision Tree
dt_model = DecisionTreeRegressor()
dt_model.fit(X_train, y_train)
predictions_dt = dt_model.predict(X_test)

Шаг 3: Оценка качества моделей

Регрессионные модели машинного обучения традиционно оцениваются с помощью MSE, MAPE и RMSE для определения их эффективности.

from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error

def calculate_metrics(y_true, y_pred):
    mse = mean_squared_error(y_true, y_pred)
    mape = mean_absolute_percentage_error(y_true, y_pred)
    rmse = mean_squared_error(y_true, y_pred, squared=False)
    return mse, mape, rmse

# Compute metrics for each model
mse_linear, mape_linear, rmse_linear = calculate_metrics(y_test, predictions_linear)
mse_rf, mape_rf, rmse_rf = calculate_metrics(y_test, predictions_rf)
mse_dt, mape_dt, rmse_dt = calculate_metrics(y_test, predictions_dt)

# For Linear Regression
print('Linear Regression Metrics:')
print('Mean Squared Error (MSE):', mse_linear)
print('Mean Absolute Percentage Error (MAPE):', mape_linear)
print('Root Mean Squared Error (RMSE):', rmse_linear)
print('\n')

# For Random Forest Regression
print('Random Forest Regression Metrics:')
print('Mean Squared Error (MSE):', mse_rf)
print('Mean Absolute Percentage Error (MAPE):', mape_rf)
print('Root Mean Squared Error (RMSE):', rmse_rf)
print('\n')

# For Decision Tree
print('Decision Tree Metrics:')
print('Mean Squared Error (MSE):', mse_dt)
print('Mean Absolute Percentage Error (MAPE):', mape_dt)
print('Root Mean Squared Error (RMSE):', rmse_dt)

Подсчет метрик MSE, MAPE, RMSE для моделей машинного обучения

Рис. 19: Подсчет метрик MSE, MAPE, RMSE для моделей машинного обучения

По этим показателям регрессия Random Forest является самой эффективной моделью из всех трех. У нее самые низкие показатели MSE, MAPE и RMSE, что говорит не только о наименьших средних квадратичных ошибках (MSE и RMSE), но и о наименьшей средней процентной ошибке (MAPE).

Напротив, линейная регрессия показала наихудшие результаты на этом наборе данных, имея самые высокие значения по всем 3 метрикам. Модель Decision Tree занимает среднее положение, имея лучшие показатели, чем Linear Regression, но не такие хорошие, как Random Forest.

Выводы

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