Разработка, оценка и присвоение оценки модели прогнозирования по продажам супермаркета
В этом руководстве представлен полный пример рабочего процесса Обработки и анализа данных Synapse в Microsoft Fabric. Сценарий создает модель прогнозирования, которая использует исторические данные о продажах для прогнозирования продаж категорий товаров в гипермаркете.
Прогнозирование является важным активом в продажах. Он объединяет исторические данные и прогнозные методы для предоставления аналитических сведений о будущих тенденциях. Прогнозирование может анализировать прошлые продажи, чтобы определить закономерности и узнать о поведении потребителей для оптимизации инвентаризации, производства и маркетинговых стратегий. Этот упреждающий подход повышает адаптируемость, скорость реагирования и общую производительность предприятий в условиях динамичного рынка.
В этом руководстве рассматриваются следующие действия.
- Загрузка данных
- Использование анализа аналитических данных для понимания и обработки данных
- Обучение модели машинного обучения с помощью пакета программного обеспечения с открытым исходным кодом и отслеживание экспериментов с помощью MLflow и функции автологирования Fabric
- Сохранение конечной модели машинного обучения и прогнозирование
- Отображение производительности модели с помощью визуализаций Power BI
Необходимые условия
Получите подписку Microsoft Fabric. Или зарегистрируйте бесплатную пробную Microsoft Fabric.
Войдите в Microsoft Fabric.
Используйте переключатель интерфейса в левой нижней части домашней страницы, чтобы перейти на Fabric.
- При необходимости создайте озеро Microsoft Fabric, как описано в разделе Создание озера в Microsoft Fabric.
Следуйте инструкциям в записной книжке
Вы можете выбрать один из следующих вариантов для выполнения в записной книжке:
- Откройте и запустите встроенную записную книжку в интерфейсе Обработки и анализа данных Synapse
- Отправка записной книжки из GitHub в интерфейс Обработки и анализа данных Synapse
Открытие встроенной записной книжки
Пример записной книжки для прогнозирования продаж сопровождает это руководство.
Чтобы открыть пример ноутбука для этого руководства, следуйте инструкциям в Подготовка системы для учебников по науке о данных.
Перед началом выполнения кода обязательно подключите lakehouse к записной книжке.
Импорт записной книжки из GitHub
Записная книжка AIsample — Superstore Forecast.ipynb идет в комплекте с этим руководством.
Чтобы открыть сопровождающую записную книжку для этого руководства, следуйте инструкциям в подготовьте систему для учебных руководств по науке о данных, чтобы импортировать записную книжку в своё рабочее пространство.
Если вы хотите скопировать и вставить код на этой странице, можно создать новую записную книжку.
Не забудьте подключить lakehouse к записной книжке перед началом выполнения кода.
Шаг 1. Загрузка данных
Набор данных содержит 9995 экземпляров продаж различных продуктов. Он также включает 21 атрибутов. Эта таблица находится в файле Superstore.xlsx, используемом в этой записной книжке:
Идентификатор строки | Идентификатор заказа | Дата заказа | Дата отправки | Режим доставки | Идентификатор клиента | Имя клиента | Сегмент | Страна | Город | Государство | Почтовый индекс | Область | Идентификатор продукта | Категория | Sub-Category | Название продукта | Продажи | Количество | Скидка | Прибыль |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
4 | US-2015-108966 | 2015-10-11 | 2015-10-18 | Стандартный класс | SO-20335 | Шон О'Доннелл | Потребитель | США | Форт Лодердейл | Флорида | 33311 | Юг | FUR-TA-10000577 | Мебель | Таблицы | Стол серии Bretford CR4500, тонкий прямоугольный стол. | 957,5775 | 5 | 0.45 | -383.0310 |
11 | CA-2014-115812 | 2014-06-09 | 2014-06-09 | Стандартный класс | Стандартный класс | Brosina Хоффман | Потребитель | США | Лос-Анджелес | Калифорния | 90032 | Запад | FUR-TA-10001539 | Мебель | Таблицы | Столы для конференций Chromcraft прямоугольной формы | 1706.184 | 9 | 0.2 | 85.3092 |
31 | US-2015-150630 | 2015-09-17 | 2015-09-21 | Стандартный класс | ТБ-21520 | Трейси Блюмштейн | Потребитель | США | Филадельфия | Пенсильвания | 19140 | Восток | OFF-EN-10001509 | Канцелярские товары | Конверты | Пластиковые конверты с завязками на веревочках | 3,264 | 2 | 0.2 | 1.1016 |
Определите эти параметры, чтобы использовать эту записную книжку с различными наборами данных:
IS_CUSTOM_DATA = False # If TRUE, the dataset has to be uploaded manually
IS_SAMPLE = False # If TRUE, use only rows of data for training; otherwise, use all data
SAMPLE_ROWS = 5000 # If IS_SAMPLE is True, use only this number of rows for training
DATA_ROOT = "/lakehouse/default"
DATA_FOLDER = "Files/salesforecast" # Folder with data files
DATA_FILE = "Superstore.xlsx" # Data file name
EXPERIMENT_NAME = "aisample-superstore-forecast" # MLflow experiment name
Скачайте набор данных и отправьте его в lakehouse
Этот код загружает общедоступную версию набора данных, а затем сохраняет ее в озере данных Fabric.
Важный
Перед запуском записной книжки обязательно добавить lakehouse. В противном случае вы получите ошибку.
import os, requests
if not IS_CUSTOM_DATA:
# Download data files into the lakehouse if they're not already there
remote_url = "https://synapseaisolutionsa.blob.core.windows.net/public/Forecast_Superstore_Sales"
file_list = ["Superstore.xlsx"]
download_path = "/lakehouse/default/Files/salesforecast/raw"
if not os.path.exists("/lakehouse/default"):
raise FileNotFoundError(
"Default lakehouse not found, please add a lakehouse and restart the session."
)
os.makedirs(download_path, exist_ok=True)
for fname in file_list:
if not os.path.exists(f"{download_path}/{fname}"):
r = requests.get(f"{remote_url}/{fname}", timeout=30)
with open(f"{download_path}/{fname}", "wb") as f:
f.write(r.content)
print("Downloaded demo data files into lakehouse.")
Настройка отслеживания экспериментов MLflow
Microsoft Fabric автоматически фиксирует значения входных параметров и выходных метрик модели машинного обучения при обучении. Это расширяет возможности автологирования MLflow. Затем данные записываются в рабочую область, где можно получить доступ и визуализировать его с помощью API MLflow или соответствующего эксперимента в рабочей области. Дополнительные сведения об автологировании см. в статье Автологирование в Microsoft Fabric.
Чтобы отключить автоматическую запись Microsoft Fabric в сеансе записной книжки, вызовите mlflow.autolog()
и задайте disable=True
:
# Set up MLflow for experiment tracking
import mlflow
mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True) # Turn off MLflow autologging
Чтение необработанных данных из lakehouse
Чтение необработанных данных из раздела "Файлы " хранилища. Добавьте дополнительные столбцы для разных частей дат. Те же сведения используются для создания секционированных разностных таблиц. Так как необработанные данные хранятся в виде файла Excel, необходимо использовать pandas для его чтения:
import pandas as pd
df = pd.read_excel("/lakehouse/default/Files/salesforecast/raw/Superstore.xlsx")
Шаг 2. Выполнение анализа аналитических данных
Импорт библиотек
Перед любым анализом импортируйте необходимые библиотеки:
# Importing required libraries
import warnings
import itertools
import numpy as np
import matplotlib.pyplot as plt
warnings.filterwarnings("ignore")
plt.style.use('fivethirtyeight')
import pandas as pd
import statsmodels.api as sm
import matplotlib
matplotlib.rcParams['axes.labelsize'] = 14
matplotlib.rcParams['xtick.labelsize'] = 12
matplotlib.rcParams['ytick.labelsize'] = 12
matplotlib.rcParams['text.color'] = 'k'
from sklearn.metrics import mean_squared_error,mean_absolute_percentage_error
Отображение необработанных данных
Вручную просмотрите подмножество данных, чтобы лучше понять сам набор данных и использовать функцию display
для печати кадра данных. Кроме того, представления Chart
могут легко визуализировать подмножества набора данных.
display(df)
В этом документе основная задача заключается в прогнозировании продаж категории Furniture
. Это ускоряет вычисление и помогает показать производительность модели. Однако эта записная книжка использует адаптируемые методы. Эти методы можно расширить для прогнозирования продаж других категорий продуктов.
# Select "Furniture" as the product category
furniture = df.loc[df['Category'] == 'Furniture']
print(furniture['Order Date'].min(), furniture['Order Date'].max())
Предварительная обработка данных
Реальные бизнес-сценарии часто требуют прогнозирования продаж в трех разных категориях:
- Определенная категория продукта
- Определенная категория клиента
- Определенная комбинация категории продуктов и категории клиентов
Сначала удалите ненужные столбцы для предварительной обработки данных. Некоторые столбцы (Row ID
, Order ID
,Customer ID
и Customer Name
) являются ненужными, так как они не влияют. Мы хотим прогнозировать общий объем продаж по всему штату и региону для определенной категории продуктов (Furniture
), чтобы мы могли удалить столбцы State
, Region
, Country
, City
и Postal Code
. Чтобы прогнозировать продажи для определенного расположения или категории, может потребоваться соответствующим образом настроить этап предварительной обработки.
# Data preprocessing
cols = ['Row ID', 'Order ID', 'Ship Date', 'Ship Mode', 'Customer ID', 'Customer Name',
'Segment', 'Country', 'City', 'State', 'Postal Code', 'Region', 'Product ID', 'Category',
'Sub-Category', 'Product Name', 'Quantity', 'Discount', 'Profit']
# Drop unnecessary columns
furniture.drop(cols, axis=1, inplace=True)
furniture = furniture.sort_values('Order Date')
furniture.isnull().sum()
Набор данных структурирован ежедневно. Мы должны переобработать данные на столбце Order Date
, потому что мы хотим разработать модель для прогнозирования продаж на ежемесячной основе.
Сначала сгруппируйте категорию Furniture
по Order Date
. Затем вычислите сумму столбца Sales
для каждой группы, чтобы определить общее количество продаж для каждого уникального значения Order Date
. Переобразуйте столбец Sales
с частотой MS
для агрегации данных по месяцам. Наконец, вычислите среднее значение продаж за каждый месяц.
# Data preparation
furniture = furniture.groupby('Order Date')['Sales'].sum().reset_index()
furniture = furniture.set_index('Order Date')
furniture.index
y = furniture['Sales'].resample('MS').mean()
y = y.reset_index()
y['Order Date'] = pd.to_datetime(y['Order Date'])
y['Order Date'] = [i+pd.DateOffset(months=67) for i in y['Order Date']]
y = y.set_index(['Order Date'])
maximim_date = y.reset_index()['Order Date'].max()
Продемонстрировать влияние Order Date
на Sales
для категории Furniture
:
# Impact of order date on the sales
y.plot(figsize=(12, 3))
plt.show()
Перед любым статистическим анализом необходимо импортировать модуль Python statsmodels
. Он предоставляет классы и функции для оценки многих статистических моделей. Он также предоставляет классы и функции для проведения статистических тестов и статистического исследования данных.
import statsmodels.api as sm
Выполнение статистического анализа
Временный ряд отслеживает эти элементы данных с заданными интервалами, чтобы определить вариант этих элементов в шаблоне временных рядов:
уровень: фундаментальный компонент, представляющий среднее значение для определенного периода времени
тренд: описывает, уменьшается ли временный ряд, остается ли константой или увеличивается с течением времени.
сезонности: описывает периодический сигнал во временных рядах и ищет циклические вхождения, влияющие на увеличение или уменьшение тенденций временных рядов.
шум/остаточный: относится к случайным колебаниям и изменчивости в данных временных рядов, которые модель не может объяснить.
В этом коде вы увидите эти элементы для набора данных после предварительной обработки:
# Decompose the time series into its components by using statsmodels
result = sm.tsa.seasonal_decompose(y, model='additive')
# Labels and corresponding data for plotting
components = [('Seasonality', result.seasonal),
('Trend', result.trend),
('Residual', result.resid),
('Observed Data', y)]
# Create subplots in a grid
fig, axes = plt.subplots(nrows=4, ncols=1, figsize=(12, 7))
plt.subplots_adjust(hspace=0.8) # Adjust vertical space
axes = axes.ravel()
# Plot the components
for ax, (label, data) in zip(axes, components):
ax.plot(data, label=label, color='blue' if label != 'Observed Data' else 'purple')
ax.set_xlabel('Time')
ax.set_ylabel(label)
ax.set_xlabel('Time', fontsize=10)
ax.set_ylabel(label, fontsize=10)
ax.legend(fontsize=10)
plt.show()
На графиках описываются сезонность, тенденции и шум в прогнозируемых данных. Вы можете записать базовые шаблоны и разработать модели, которые делают точные прогнозы, устойчивые к случайным колебаниям.
Шаг 3. Обучение и отслеживание модели
Теперь, когда у вас есть доступные данные, определите модель прогнозирования. В этом ноутбуке примените модель прогнозирования, называемую сезонной авторегрессионной интегрированной скользящей среднею с экзогенными факторами (SARIMAX). SARIMAX объединяет авторегрессионные (AR) и скользящее среднее (MA) компоненты, сезонное дифференцирование и внешние предикторы, чтобы сделать точные и гибкие прогнозы для временных рядов.
Для отслеживания экспериментов также используется автологирование MLflow и Fabric. Здесь загрузите дельта-таблицу из lakehouse. Вы можете использовать другие разностные таблицы, которые рассматривают lakehouse в качестве источника.
# Import required libraries for model evaluation
from sklearn.metrics import mean_squared_error, mean_absolute_percentage_error
Настройка гиперпараметров
SARIMAX учитывает параметры, используемые в регулярной авторегрессионной интегрированной модели скользящего среднего (ARIMA) (p
, d
, q
), и добавляет параметры сезонности (P
, D
, Q
, s
). Эти аргументы модели SARIMAX называются порядка (p
, d
, q
) и сезонных (P
, D
, Q
, s
соответственно). Поэтому для обучения модели необходимо сначала настроить семь параметров.
Параметры заказа:
p
: порядок компонента AR, представляющий количество прошлых наблюдений в временных рядах, используемых для прогнозирования текущего значения.Как правило, этот параметр должен быть неотрицательное целое число. Общие значения находятся в диапазоне
0
до3
, хотя более высокие значения возможны в зависимости от конкретных характеристик данных. Более высокое значениеp
указывает на длинную память прошлых значений в модели.d
: разностный порядок, представляющий количество раз, которое временной ряд нужно дифференцировать для достижения стационарности.Этот параметр должен быть неотрицательное целое число. Общие значения находятся в диапазоне
0
до2
. Значениеd
0
означает, что временной ряд уже является стационарным. Более высокие значения указывают количество разных операций, необходимых для того, чтобы сделать его стационарным.q
: порядок компонента MA, представляющий число прошлых терминов ошибки белого шума, используемых для прогнозирования текущего значения.Этот параметр должен быть неотрицательное целое число. Общие значения находятся в диапазоне
0
до3
, но для определенных временных рядов могут потребоваться более высокие значения. Более высокое значениеq
указывает на более сильную зависимость от прошлых ошибок для прогнозирования.
Параметры сезонного заказа:
-
P
: сезонный порядок компонента AR, аналогичныйp
, но для сезонной части -
D
: сезонный порядок дифференцирования, аналогичныйd
, но применяемый для сезонной части -
Q
: сезонный порядок компонента MA, аналогичныйq
, но для сезонной части -
s
: количество шагов времени на сезонный цикл (например, 12 для ежемесячных данных с ежегодной сезонностью)
# Hyperparameter tuning
p = d = q = range(0, 2)
pdq = list(itertools.product(p, d, q))
seasonal_pdq = [(x[0], x[1], x[2], 12) for x in list(itertools.product(p, d, q))]
print('Examples of parameter combinations for Seasonal ARIMA...')
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[1]))
print('SARIMAX: {} x {}'.format(pdq[1], seasonal_pdq[2]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[3]))
print('SARIMAX: {} x {}'.format(pdq[2], seasonal_pdq[4]))
SARIMAX имеет другие параметры:
enforce_stationarity
: Нужно ли применять стационарность к данным временных рядов, прежде чем использовать модель SARIMAX.Если для
enforce_stationarity
задано значениеTrue
(по умолчанию), это указывает, что модель SARIMAX должна применять стационарность к данным временных рядов. Затем модель SARIMAX автоматически применяет разности к данным, чтобы сделать их стационарными, как указано в порядкахd
иD
, до подгонки модели. Это распространенная практика, так как многие модели временных рядов, включая SARIMAX, предполагают, что данные являются стационарными.Для нестационарных временных рядов (например, если они демонстрируют тенденции или сезонность), рекомендуется установить
enforce_stationarity
вTrue
и позволить модели SARIMAX выполнять дифференцирование для достижения стационарности. Для стационных временных рядов (например, один без тенденций или сезонности), задайтеenforce_stationarity
False
, чтобы избежать ненужных отличий.enforce_invertibility
: определяет, должна ли модель применять обратимость для оцененных параметров во время процесса оптимизации.Если для
enforce_invertibility
задано значениеTrue
(по умолчанию), это означает, что модель SARIMAX должна принудительно применять обратимость для предполагаемых параметров. Инвертируемость гарантирует, что модель хорошо определена, и что оцененные коэффициенты AR и MA находятся в пределах диапазона стационарности.Принудительное применение инвертируемости помогает обеспечить соответствие модели SARIMAX теоретическим требованиям для стабильной модели временных рядов. Это также помогает предотвратить проблемы с оценкой модели и стабильностью.
По умолчанию используется модель AR(1)
. Это относится к (1, 0, 0)
. Обычной практикой является пробовать различные сочетания параметров порядка и сезонных параметров порядка и оценивать производительность модели для набора данных. Соответствующие значения могут отличаться от одного временных рядов к другому.
Определение оптимальных значений часто включает анализ функции автозамены (ACF) и частичной функции автозамены (PACF) данных временных рядов. Он также часто включает в себя использование критериев выбора модели, например критерия информации Akaike (AIC) или критерия информации Байеса (BIC).
Настройте гиперпараметры:
# Tune the hyperparameters to determine the best model
for param in pdq:
for param_seasonal in seasonal_pdq:
try:
mod = sm.tsa.statespace.SARIMAX(y,
order=param,
seasonal_order=param_seasonal,
enforce_stationarity=False,
enforce_invertibility=False)
results = mod.fit(disp=False)
print('ARIMA{}x{}12 - AIC:{}'.format(param, param_seasonal, results.aic))
except:
continue
После оценки предыдущих результатов можно определить значения для параметров заказа и сезонных параметров заказа. Выбор — это order=(0, 1, 1)
и seasonal_order=(0, 1, 1, 12)
, которые предлагают самый низкий AIC (например, 279,58). Используйте эти значения для обучения модели.
Обучение модели
# Model training
mod = sm.tsa.statespace.SARIMAX(y,
order=(0, 1, 1),
seasonal_order=(0, 1, 1, 12),
enforce_stationarity=False,
enforce_invertibility=False)
results = mod.fit(disp=False)
print(results.summary().tables[1])
Этот код визуализирует прогноз временных рядов для данных о продажах мебели. В диаграммах отображаются как наблюдаемые данные, так и прогноз на один шаг вперед, с затеняемой областью для доверительного интервала.
# Plot the forecasting results
pred = results.get_prediction(start=maximim_date, end=maximim_date+pd.DateOffset(months=6), dynamic=False) # Forecast for the next 6 months (months=6)
pred_ci = pred.conf_int() # Extract the confidence intervals for the predictions
ax = y['2019':].plot(label='observed')
pred.predicted_mean.plot(ax=ax, label='One-step ahead forecast', alpha=.7, figsize=(12, 7))
ax.fill_between(pred_ci.index,
pred_ci.iloc[:, 0],
pred_ci.iloc[:, 1], color='k', alpha=.2)
ax.set_xlabel('Date')
ax.set_ylabel('Furniture Sales')
plt.legend()
plt.show()
# Validate the forecasted result
predictions = results.get_prediction(start=maximim_date-pd.DateOffset(months=6-1), dynamic=False)
# Forecast on the unseen future data
predictions_future = results.get_prediction(start=maximim_date+ pd.DateOffset(months=1),end=maximim_date+ pd.DateOffset(months=6),dynamic=False)
Используйте predictions
для оценки производительности модели, сравнивая с фактическими значениями. Значение predictions_future
указывает на будущее прогнозирование.
# Log the model and parameters
model_name = f"{EXPERIMENT_NAME}-Sarimax"
with mlflow.start_run(run_name="Sarimax") as run:
mlflow.statsmodels.log_model(results,model_name,registered_model_name=model_name)
mlflow.log_params({"order":(0,1,1),"seasonal_order":(0, 1, 1, 12),'enforce_stationarity':False,'enforce_invertibility':False})
model_uri = f"runs:/{run.info.run_id}/{model_name}"
print("Model saved in run %s" % run.info.run_id)
print(f"Model URI: {model_uri}")
mlflow.end_run()
# Load the saved model
loaded_model = mlflow.statsmodels.load_model(model_uri)
Шаг 4. Оценка модели и сохранение прогнозов
Интеграция фактических значений с прогнозируемыми значениями для создания отчета Power BI. Сохраните эти результаты в таблице в лейкхаусе.
# Data preparation for Power BI visualization
Future = pd.DataFrame(predictions_future.predicted_mean).reset_index()
Future.columns = ['Date','Forecasted_Sales']
Future['Actual_Sales'] = np.NAN
Actual = pd.DataFrame(predictions.predicted_mean).reset_index()
Actual.columns = ['Date','Forecasted_Sales']
y_truth = y['2023-02-01':]
Actual['Actual_Sales'] = y_truth.values
final_data = pd.concat([Actual,Future])
# Calculate the mean absolute percentage error (MAPE) between 'Actual_Sales' and 'Forecasted_Sales'
final_data['MAPE'] = mean_absolute_percentage_error(Actual['Actual_Sales'], Actual['Forecasted_Sales']) * 100
final_data['Category'] = "Furniture"
final_data[final_data['Actual_Sales'].isnull()]
input_df = y.reset_index()
input_df.rename(columns = {'Order Date':'Date','Sales':'Actual_Sales'}, inplace=True)
input_df['Category'] = 'Furniture'
input_df['MAPE'] = np.NAN
input_df['Forecasted_Sales'] = np.NAN
# Write back the results into the lakehouse
final_data_2 = pd.concat([input_df,final_data[final_data['Actual_Sales'].isnull()]])
table_name = "Demand_Forecast_New_1"
spark.createDataFrame(final_data_2).write.mode("overwrite").format("delta").save(f"Tables/{table_name}")
print(f"Spark DataFrame saved to delta table: {table_name}")
Шаг 5. Визуализация в Power BI
В отчете Power BI показана средняя абсолютная процентная ошибка (MAPE) 16,58. Метрика MAPE определяет точность метода прогнозирования. Он представляет точность прогнозируемых значений в сравнении с фактическими значениями.
MAPE — это простая метрика. 10% MAPE представляет, что среднее отклонение между прогнозируемыми значениями и фактическими значениями равно 10%независимо от того, было ли отклонение положительным или отрицательным. Стандарты желательных значений MAPE различаются в разных отраслях.
Светлая синяя линия в этом графе представляет фактические значения продаж. Темно-синяя линия представляет прогнозируемые значения продаж. Сравнение фактических и прогнозируемых продаж показывает, что модель эффективно прогнозирует продажи для категории Furniture
в течение первых шести месяцев 2023 года.
Основываясь на этом наблюдении, мы можем быть уверенными в возможностях прогнозирования модели для общих продаж за последние шесть месяцев 2023 года и в их продолжении в 2024 году. Эта уверенность может влиять на стратегические решения в области управления запасами, закупки сырьевых материалов и другие вопросы, связанные с бизнесом.
Связанное содержимое
- Использование записных книжек Microsoft Fabric
- модель машинного обучения в Microsoft Fabric
- Обучение моделей машинного обучения
- эксперименты машинного обучения в Microsoft Fabric