開發、評估和評分超級商店銷售的預測模型
本教學課程提供 Microsoft Fabric 中 Synapse 資料科學 工作流程的端對端範例。 此案例會建置預測模型,該模型會使用歷史銷售數據來預測超市的產品類別銷售。
預測是銷售中的重要資產。 它會結合歷史數據和預測方法,以提供未來趨勢的見解。 預測可以分析過去的銷售以識別模式,並從取用者行為中學習,以優化庫存、生產和行銷策略。 此主動式方法可增強動態市集中企業的適應性、回應性和整體效能。
本教學課程涵蓋下列步驟:
- 載入資料
- 使用探勘數據分析來了解和處理數據
- 使用開放原始碼軟體套件定型機器學習模型,並使用 MLflow 和網狀架構自動記錄功能來追蹤實驗
- 儲存最終的機器學習模型,並進行預測
- 使用Power BI視覺效果顯示模型效能
必要條件
取得 Microsoft Fabric 訂用 帳戶。 或者,註冊免費的 Microsoft Fabric 試用版。
登入 Microsoft Fabric。
使用首頁左側的體驗切換器,切換至 Synapse 資料科學 體驗。
- 如有必要,請建立 Microsoft Fabric lakehouse,如在 Microsoft Fabric 中建立 lakehouse 中所述。
在筆記本中跟著
您可以選擇下列其中一個選項,以遵循筆記本:
- 在 Synapse 資料科學 體驗中開啟並執行內建筆記本
- 將筆記本從 GitHub 上傳至 Synapse 資料科學 體驗
開啟內建筆記本
本教學課程隨附銷售預測筆記本範例。
若要在 Synapse 資料科學 體驗中開啟教學課程的內建範例筆記本:
移至 Synapse 資料科學 首頁。
選取 [ 使用範例]。
選取對應的範例:
- 如果範例適用於 Python 教學課程,請從預設 的端對端工作流程 (Python) 索引標籤。
- 如果範例適用於 R 教學課程,請從 [端對端工作流程] 索引標籤。
- 如果範例適用於快速教學課程,請從 [ 快速教學 課程] 索引卷標。
從 GitHub 匯入筆記本
AIsample - Superstore Forecast.ipynb 筆記本會伴隨本教學課程。
若要開啟本教學課程隨附的筆記本,請遵循準備系統以進行數據科學教學課程中的指示,將筆記本匯入您的工作區。
如果您想要複製並貼上此頁面中的程式碼,您可以 建立新的筆記本。
開始執行程序代碼之前,請務必將 Lakehouse 附加至筆記本 。
步驟 1:載入數據
數據集包含各種產品的9,995個銷售實例。 它也包含21個屬性。 此數據表來自 此筆記本中使用的Superstore.xlsx 檔案:
資料列識別碼 | 訂單識別碼 | 訂單日期 | 出貨日期 | 出貨模式 | 客戶識別碼 | 客戶名稱 | 區段 | Country | 縣/市 | 州/省 | 郵遞區號 | 區域 | 產品識別碼 | 類別 | 子類別 | 產品名稱 | Sales | 數量 | 折扣 | 收益 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
4 | US-2015-108966 | 2015-10-11 | 2015-10-18 | 標準類別 | SO-20335 | 肖恩·奧唐內爾 | 消費者 | 美國 | 勞德代爾 | 佛羅里達州 | 33311 | 南 | FUR-TA-10000577 | 傢俱 | 資料表 | 佈雷特福德 CR4500 系列苗條矩形表格 | 957.5775 | 5 | 0.45 | -383.0310 |
11 | CA-2014-115812 | 2014-06-09 | 2014-06-09 | 標準類別 | 標準類別 | 布羅西娜·霍夫曼 | 消費者 | 美國 | Los Angeles | 加州 | 90032 | West | FUR-TA-10001539 | 傢俱 | 資料表 | Chromcraft 矩形會議表格 | 1706.184 | 9 | 0.2 | 85.3092 |
31 | US-2015-150630 | 2015-09-17 | 2015-09-21 | 標準類別 | TB-21520 | 特蕾西·布盧姆斯坦 | 消費者 | 美國 | 費城 | 賓夕法尼亞州 | 19140 | 東 | OFF-EN-10001509 | 辦公室用品 | 信封 | Poly 字串系結信封 | 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 中:
重要
在執行筆記本之前, 請務必將 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 自動記錄功能。 然後,資訊會記錄到工作區,您可以在該工作區中使用 MLflow API 或工作區中的對應實驗來存取並加以可視化。 若要深入了解自動記錄,請參閱 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 讀取原始數據
從 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
式來列印 DataFrame。 此外,檢視 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
一值的總銷售額。 使用MS
頻率重新取樣Sales
數據行,以依月份匯總數據。 最後,計算每個月的平均銷售值。
# 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()
示範類別對 Furniture
的影響Order Date
Sales
:
# Impact of order date on the sales
y.plot(figsize=(12, 3))
plt.show()
在進行任何統計分析之前,您必須匯入 statsmodels
Python 模組。 它提供類別和函式來估計許多統計模型。 它也提供類別和函式來執行統計測試和統計數據探索。
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
P
、 Q
s
d
D
。 q
這些 SARIMAX 模型自變數分別稱為 order (p
、 、 q
) 和季節性順序 (P
、 D
d
、 、 s
Q
因此,若要定型模型,我們必須先微調七個參數。
順序參數:
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)和部分自動更正函式。 它通常也涉及使用模型選取準則-例如,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報表。 將這些結果儲存在 Lakehouse 內的數據表中。
# 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值標準會因產業而異。
此圖表中的淺藍色線條代表實際的銷售值。 深藍色線條代表預測的銷售值。 實際和預測銷售的比較顯示,模型在2023年上半年有效地預測該類別的銷售 Furniture
。
根據此觀察,我們可以對模型預測功能有信心,2023 年過去 6 個月的整體銷售額,並延伸到 2024 年。 這種信心可以通知有關庫存管理、原材料採購和其他商務相關考慮的戰略決策。
相關內容
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應