共用方式為


定型和評估時間序列預測模型

在此筆記本中,我們會建置程式來預測具有季節性週期的時間序列數據。 我們使用 NYC 屬性銷售數據集,日期範圍從 2003 年到 2015 年,由 NYC 財務部在 NYC 開放數據入口網站上發佈。

必要條件

在筆記本中跟著

您可以在筆記本中遵循下列兩種方式的其中一種:

  • 在 Synapse 資料科學 體驗中開啟並執行內建筆記本。
  • 將筆記本從 GitHub 上傳至 Synapse 資料科學 體驗。

開啟內建筆記本

本教學課程隨附範例 時間序列 筆記本。

若要在 Synapse 資料科學 體驗中開啟教學課程的內建範例筆記本:

  1. 移至 Synapse 資料科學 首頁。

  2. 選取 [ 使用範例]。

  3. 選取對應的範例:

    • 如果範例適用於 Python 教學課程,請從預設 的端對端工作流程 (Python) 索引標籤。
    • 如果範例適用於 R 教學課程,請從 [端對端工作流程] 索引標籤。
    • 如果範例適用於快速教學課程,請從 [ 快速教學 課程] 索引卷標。
  4. 開始執行程序代碼之前,請先將 Lakehouse 附加至筆記本

從 GitHub 匯入筆記本

AIsample - 時間序列 Forecasting.ipynb 是本教學課程隨附的筆記本。

若要開啟本教學課程隨附的筆記本,請遵循準備系統以進行數據科學教學課程中的指示,將筆記本匯入您的工作區。

如果您想要複製並貼上此頁面中的程式碼,您可以 建立新的筆記本

開始執行程序代碼之前,請務必將 Lakehouse 附加至筆記本

步驟 1:安裝自訂連結庫

當您開發機器學習模型或處理臨機操作數據分析時,您可能需要快速安裝 Apache Spark 會話的自定義連結庫(例如 prophet ,在此筆記本中)。 若要這樣做,您有兩個選項。

  1. 您可以使用內嵌安裝功能(例如、 %pip%conda等等)快速開始使用新的連結庫。 這隻會在目前的筆記本中安裝自定義連結庫,而不是在工作區中。
# Use pip to install libraries
%pip install <library name>

# Use conda to install libraries
%conda install <library name>
  1. 或者,您可以建立 Fabric 環境、從公用來源安裝連結庫,或將自定義連結庫上傳至該環境,然後您的工作區系統管理員可以將環境附加為工作區的預設值。 然後,環境中的所有連結庫都可供在工作區中的任何筆記本和Spark作業定義中使用。 如需環境的詳細資訊,請參閱 在 Microsoft Fabric 中建立、設定及使用環境。

針對此筆記本,您可以使用 %pip install 來安裝連結 prophet 庫。 PySpark 核心會在 之後 %pip install重新啟動。 這表示您必須先安裝連結庫,才能執行任何其他數據格。

# Use pip to install Prophet
%pip install prophet

步驟 2:載入數據

資料集

此筆記本會使用 NYC 屬性銷售數據數據集。 它涵蓋從 2003 年到 2015 年的數據,由 NYC 財務部在 NYC 開放數據入口網站上發佈。

數據集包含紐約市房地產市場每棟建築銷售的記錄,在13年內。 如需數據集中數據行的定義,請參閱屬性銷售檔案詞彙詞彙。

borough 鄰居 building_class_category tax_class block 很多 eastment building_class_at_present address apartment_number zip_code residential_units commercial_units total_units land_square_feet gross_square_feet year_built tax_class_at_time_of_sale building_class_at_time_of_sale sale_price sale_date
Manhattan 字母城 07 出租 - 無電梯公寓 0.0 384.0 17.0 C4 225 東二街 10009.0 10.0 0.0 10.0 2145.0 6670.0 1900.0 2.0 C4 275000.0 2007-06-19
Manhattan 字母城 07 出租 - 無電梯公寓 2.0 405.0 12.0 C7 508 東 12 街 10009.0 28.0 2.0 30.0 3872.0 15428.0 1930.0 2.0 C7 7794005.0 2007-05-21

目標是根據歷程記錄數據,建置預測每月總銷售額的模型。 為此,您使用先知,這是 Facebook 開發的 開放原始碼 預測連結庫。 先知以加法模型為基礎,其中非線性趨勢符合每日、每周和每年季節性和假日效果。 先知最適合具有強烈季節性影響的時間序列數據集,以及數個歷史數據季節。 此外,先知會強固地處理遺漏的數據和數據極端值。

先知使用可分解的時間序列模型,其中包含三個元件:

  • 趨勢:先知假設有一個單項常數的成長率,並自動變更點選取
  • 季節性:根據預設,先知會使用 Fourier 系列來符合每周和每年的季節性
  • 假期:先知需要所有過去和未來的假期。 如果假期將來不重複,先知就不會在預測中包含它。

此筆記本會每月匯總數據,因此會忽略假日。

如需先知模型化技術的詳細資訊,請閱讀 官方檔

下載數據集,並上傳至 Lakehouse

數據源包含15 .csv 個檔案。 這些檔案包含 2003 年至 2015 年間紐約五個區的屬性銷售記錄。 為了方便起見,檔案 nyc_property_sales.tar 會保存所有這些 .csv 檔案,將它們壓縮成一個檔案。 公開可用的 Blob 記憶體會裝載此 .tar 檔案。

提示

透過此程式代碼資料格中顯示的參數,您可以輕鬆地將此筆記本套用至不同的資料集。

URL = "https://synapseaisolutionsa.blob.core.windows.net/public/NYC_Property_Sales_Dataset/"
TAR_FILE_NAME = "nyc_property_sales.tar"
DATA_FOLDER = "Files/NYC_Property_Sales_Dataset"
TAR_FILE_PATH = f"/lakehouse/default/{DATA_FOLDER}/tar/"
CSV_FILE_PATH = f"/lakehouse/default/{DATA_FOLDER}/csv/"

EXPERIMENT_NAME = "aisample-timeseries" # MLflow experiment name

此程式代碼會下載公開可用的數據集版本,然後將該數據集儲存在 Fabric Lakehouse 中。

重要

在執行筆記本之前,請務必 先將 Lakehouse 新增至筆記本。 若無法這麼做,將會導致錯誤。

import os

if not os.path.exists("/lakehouse/default"):
    # Add a lakehouse if the notebook has no default lakehouse
    # A new notebook will not link to any lakehouse by default
    raise FileNotFoundError(
        "Default lakehouse not found, please add a lakehouse for the notebook."
    )
else:
    # Verify whether or not the required files are already in the lakehouse, and if not, download and unzip
    if not os.path.exists(f"{TAR_FILE_PATH}{TAR_FILE_NAME}"):
        os.makedirs(TAR_FILE_PATH, exist_ok=True)
        os.system(f"wget {URL}{TAR_FILE_NAME} -O {TAR_FILE_PATH}{TAR_FILE_NAME}")

    os.makedirs(CSV_FILE_PATH, exist_ok=True)
    os.system(f"tar -zxvf {TAR_FILE_PATH}{TAR_FILE_NAME} -C {CSV_FILE_PATH}")

開始錄製此筆記本的運行時間。

# Record the notebook running time
import time

ts = time.time()

設定 MLflow 實驗追蹤

若要擴充 MLflow 記錄功能,自動記錄會在定型期間自動擷取機器學習模型的輸入參數和輸出計量值。 此資訊接著會記錄到工作區,其中 MLflow API 或工作區中的對應實驗可以存取並可視化。 如需自動記錄的詳細資訊,請造訪 此資源

# Set up the MLflow experiment
import mlflow

mlflow.set_experiment(EXPERIMENT_NAME)
mlflow.autolog(disable=True)  # Disable MLflow autologging

注意

如果您要停用筆記本工作階段中的 Microsoft Fabric 自動記錄,請呼叫 mlflow.autolog() 並設定 disable=True

從 Lakehouse 讀取原始日期數據

df = (
    spark.read.format("csv")
    .option("header", "true")
    .load("Files/NYC_Property_Sales_Dataset/csv")
)

步驟 3:開始探勘數據分析

若要檢閱數據集,您可以手動檢查數據子集,以進一步了解數據集。 您可以使用 函式 display 來列印 DataFrame。 您也可以顯示圖表檢視,以便輕鬆地將數據集的子集可視化。

display(df)

手動檢閱數據集會導致一些早期觀察:

  • $0.00 銷售價格的實例。 根據 詞彙詞彙,這意味著轉讓擁有權,沒有現金考慮。 換句話說,交易中沒有現金流動。 您應該從數據集中移除具有 $0.00 sales_price 值的銷售額。

  • 數據集涵蓋不同的建置類別。 不過,此筆記本將著重於住宅建築,根據 詞彙詞彙,標示為“A”類型。 您應該篩選數據集,只包含住宅建築。 若要這樣做,請包含 building_class_at_time_of_sale 或資料 building_class_at_present 行。 您只能包含 building_class_at_time_of_sale 資料。

  • 數據集包含值等於 0 或gross_square_feet值等於 0 的實例total_units。 您應該移除所有實例,其中 total_unitsgross_square_units 值等於 0。

  • 某些資料行 - 例如 、 apartment_numbertax_classbuild_class_at_present、 等 - 有遺漏或 NULL 值。 假設遺漏的數據牽涉到 Clerical 錯誤或不存在的數據。 分析不取決於這些遺漏值,因此您可以忽略這些值。

  • 數據 sale_price 行會儲存為字串,前面加上 “$” 字元。 若要繼續進行分析,請將此數據行表示為數位。 您應該將資料 sale_price 行轉換成整數。

類型轉換和篩選

若要解決某些已識別的問題,請匯入必要的連結庫。

# Import libraries
import pyspark.sql.functions as F
from pyspark.sql.types import *

將銷售數據從字串轉換成整數

使用正則表達式來分隔字串的數值部分與貨幣符號(例如,在字串 “$300,000” 中,分割 “$” 和 “300,000”),然後將數值部分轉換成整數。

接下來,篩選數據,只包含符合下列所有條件的實例:

  1. sales_price大於 0
  2. total_units大於 0
  3. gross_square_feet大於 0
  4. building_class_at_time_of_sale類型為 A
df = df.withColumn(
    "sale_price", F.regexp_replace("sale_price", "[$,]", "").cast(IntegerType())
)
df = df.select("*").where(
    'sale_price > 0 and total_units > 0 and gross_square_feet > 0 and building_class_at_time_of_sale like "A%"'
)

每月匯總

數據資源會每天追蹤屬性銷售,但此方法對於此筆記本而言太細微。 相反地,請每月匯總數據。

首先,變更日期值,只顯示月份和年份數據。 日期值仍會包含年份數據。 例如,您仍然可以區分 2005 年 12 月和 2006 年 12 月。

此外,只保留與分析相關的數據行。 這些包括sales_pricetotal_unitsgross_square_feetsales_date。 您必須重新命名 sales_datemonth

monthly_sale_df = df.select(
    "sale_price",
    "total_units",
    "gross_square_feet",
    F.date_format("sale_date", "yyyy-MM").alias("month"),
)
display(monthly_sale_df)

sale_price依月份匯總、 total_unitsgross_square_feet 值。 然後,依 month將數據分組,並加總每個群組中的所有值。

summary_df = (
    monthly_sale_df.groupBy("month")
    .agg(
        F.sum("sale_price").alias("total_sales"),
        F.sum("total_units").alias("units"),
        F.sum("gross_square_feet").alias("square_feet"),
    )
    .orderBy("month")
)

display(summary_df)

Pyspark 到 Pandas 轉換

Pyspark DataFrames 妥善處理大型數據集。 不過,由於數據匯總,DataFrame 大小較小。 這表示您現在可以使用 pandas DataFrame。

此程式代碼會將數據集從 pyspark DataFrame 轉換成 pandas DataFrame。

import pandas as pd

df_pandas = summary_df.toPandas()
display(df_pandas)

視覺效果

您可以檢查紐約市的房地產貿易趨勢,以進一步了解數據。 這會導致深入了解潛在模式和季節性趨勢。 在此資源深入瞭解 Microsoft Fabric 數據視覺效果

import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np

f, (ax1, ax2) = plt.subplots(2, 1, figsize=(35, 10))
plt.sca(ax1)
plt.xticks(np.arange(0, 15 * 12, step=12))
plt.ticklabel_format(style="plain", axis="y")
sns.lineplot(x="month", y="total_sales", data=df_pandas)
plt.ylabel("Total Sales")
plt.xlabel("Time")
plt.title("Total Property Sales by Month")

plt.sca(ax2)
plt.xticks(np.arange(0, 15 * 12, step=12))
plt.ticklabel_format(style="plain", axis="y")
sns.lineplot(x="month", y="square_feet", data=df_pandas)
plt.ylabel("Total Square Feet")
plt.xlabel("Time")
plt.title("Total Property Square Feet Sold by Month")
plt.show()

探勘數據分析的觀察摘要

  • 數據顯示一年一次的明顯週期性模式:這表示數據具有 每年的季節性
  • 與冬季相比,夏季月份的銷售量似乎較高
  • 相較於銷售量較高的年份和銷售量較低的年份,高銷售月份與高銷售年度銷售月份之間的收入差異超過高銷售月份與低銷售年份之間的收入差異。

例如,在 2004 年,最高銷售月份與最低銷售月份之間的營收差異大約是:

$900,000,000 - $500,000,000 = $400,000,000

對於 2011 年,該營收差異計算是關於:

$400,000,000 - $300,000,000 = $100,000,000

這在稍後變得很重要,當您必須決定乘法法季節性效果之間時。

步驟 4:模型定型和追蹤

模型調整

先知 輸入一律為兩欄 DataFrame。 一個輸入數據行是名為 ds的時間數據行,而一個輸入數據行是名為 y的值數據行。 時間資料列應該有日期、時間或日期時間資料格式(例如 )。 YYYY_MM 這裏的數據集符合該條件。 值數據行必須是數值數據格式。

針對模型調整,您只能將時間數據行重新命名為 ds 並將值數據行重新命名為 y,並將數據傳遞至先知。 如需詳細資訊, 請參閱先知 Python API 檔

df_pandas["ds"] = pd.to_datetime(df_pandas["month"])
df_pandas["y"] = df_pandas["total_sales"]

先知遵循 scikit-learn 慣例。 首先,建立先知的新實例、設定特定參數(例如,seasonality_mode),然後將該實例放入數據集。

  • 雖然常數加法因數是先知的默認季節性效果,但您應該針對季節性效果參數使用 「乘法」季節性 。 上一節的分析顯示,由於季節性幅度的變化,簡單的加法季節性完全不符合數據。

  • weekly_seasonality 參數設定為 off,因為數據依月份匯總。 因此,無法使用每周數據。

  • 使用 Markov Chain Monte Carlo (MCMC) 方法來擷取季節性不確定性估計值。 根據預設,先知可以提供趨勢和觀察雜訊的不確定性估計,但不能用於季節性。 MCMC 需要更多的處理時間,但它們可讓演算法提供季節性的不確定性估計值,以及趨勢和觀察雜訊。 如需詳細資訊,請參閱先知不確定性間隔檔

  • 透過 changepoint_prior_scale 參數調整自動變更點偵測敏感度。 先知演算法會自動嘗試在突然變更軌跡的數據中尋找實例。 很難找到正確的值。 若要解決此問題,您可以嘗試不同的值,然後選取具有最佳效能的模型。 如需詳細資訊, 請參閱先知趨勢變更點檔

from prophet import Prophet

def fit_model(dataframe, seasonality_mode, weekly_seasonality, chpt_prior, mcmc_samples):
    m = Prophet(
        seasonality_mode=seasonality_mode,
        weekly_seasonality=weekly_seasonality,
        changepoint_prior_scale=chpt_prior,
        mcmc_samples=mcmc_samples,
    )
    m.fit(dataframe)
    return m

交叉驗證

先知有內建的交叉驗證工具。 此工具可以估計預測錯誤,並找出具有最佳效能的模型。

交叉驗證技術可以驗證模型效率。 這項技術會在數據集的子集上定型模型,並在先前看不見的數據集子集上執行測試。 這項技術可以檢查統計模型如何一般化為獨立的數據集。

針對交叉驗證,請保留數據集的特定範例,該範例不屬於定型數據集的一部分。 然後,在部署之前,在該範例上測試定型的模型。 不過,這種方法不適用於時間序列數據,因為如果模型已經看到 2005 年 1 月和 2005 年 3 月的數據,而且您嘗試預測 2005 年 2 月的月份,模型基本上 可以作弊,因為它可以看到數據趨勢的潛在客戶。 在實際應用程式中,目標是預測 未來,作為看不見的區域。

若要處理此作業,並讓測試可靠,請根據日期分割數據集。 使用數據集到特定日期(例如,前11年的數據)進行定型,然後使用其餘看不見的數據進行預測。

在此案例中,從 11 年的定型數據開始,然後使用一年的地平線進行每月預測。 具體來說,定型數據包含 2003 到 2013 年的所有專案。 然後,第一次執行會處理 2014 年 1 月至 2015 年 1 月的預測。 下一個回合會處理 2014 年 2 月至 2015 年 2 月的預測,依此方式。

針對三個定型模型的每個重複此程式,以查看哪一個模型執行得最好。 然後,將這些預測與真實世界值進行比較,以建立最佳模型的預測品質。

from prophet.diagnostics import cross_validation
from prophet.diagnostics import performance_metrics

def evaluation(m):
    df_cv = cross_validation(m, initial="4017 days", period="30 days", horizon="365 days")
    df_p = performance_metrics(df_cv, monthly=True)
    future = m.make_future_dataframe(periods=12, freq="M")
    forecast = m.predict(future)
    return df_p, future, forecast

使用 MLflow 的記錄模型

記錄模型,以追蹤其參數,並儲存模型以供日後使用。 所有相關模型信息都會記錄在工作區的實驗名稱下。 模型、參數和計量以及 MLflow 自動記錄項目會儲存在一個 MLflow 執行中。

# Setup MLflow
from mlflow.models.signature import infer_signature

進行實驗

機器學習實驗可作為組織和控制的主要單位,用於所有相關的機器學習執行。 執行會對應至模型程式代碼的單一執行。 機器學習實驗追蹤是指管理所有不同的實驗及其元件。 這包括參數、計量、模型和其他成品,並有助於組織特定機器學習實驗的必要元件。 機器學習實驗追蹤也可讓您使用已儲存的實驗輕鬆重複過去的結果。 深入瞭解 Microsoft Fabric 中的機器學習實驗。 一旦您決定您想要包含的步驟(例如,調整和評估此筆記本中的先知模型),您就可以執行實驗。

model_name = f"{EXPERIMENT_NAME}-prophet"

models = []
df_metrics = []
forecasts = []
seasonality_mode = "multiplicative"
weekly_seasonality = False
changepoint_priors = [0.01, 0.05, 0.1]
mcmc_samples = 100

for chpt_prior in changepoint_priors:
    with mlflow.start_run(run_name=f"prophet_changepoint_{chpt_prior}"):
        # init model and fit
        m = fit_model(df_pandas, seasonality_mode, weekly_seasonality, chpt_prior, mcmc_samples)
        models.append(m)
        # Validation
        df_p, future, forecast = evaluation(m)
        df_metrics.append(df_p)
        forecasts.append(forecast)
        # Log model and parameters with MLflow
        mlflow.prophet.log_model(
            m,
            model_name,
            registered_model_name=model_name,
            signature=infer_signature(future, forecast),
        )
        mlflow.log_params(
            {
                "seasonality_mode": seasonality_mode,
                "mcmc_samples": mcmc_samples,
                "weekly_seasonality": weekly_seasonality,
                "changepoint_prior": chpt_prior,
            }
        )
        metrics = df_p.mean().to_dict()
        metrics.pop("horizon")
        mlflow.log_metrics(metrics)

屬性面板的螢幕快照。

使用先知將模型可視化

先知具有內建的視覺效果函式,可顯示模型適合的結果。

黑點表示用來定型模型的數據點。 藍線是預測,淺藍色區域會顯示不確定性間隔。 您已建置三個具有不同 changepoint_prior_scale 值的模型。 這三個模型的預測會顯示在此程式代碼區塊的結果中。

for idx, pack in enumerate(zip(models, forecasts)):
    m, forecast = pack
    fig = m.plot(forecast)
    fig.suptitle(f"changepoint = {changepoint_priors[idx]}")

第一個圖表中的最小值 changepoint_prior_scale 會導致趨勢變更的不足。 第三個圖表中最大的 changepoint_prior_scale 可能會導致過度學習。 因此,第二個圖表似乎是最佳選擇。 這表示第二個模型最適合。

先知也可以輕鬆地將基礎趨勢和季節性可視化。 第二個模型的視覺效果會顯示在此程式代碼區塊的結果中。

BEST_MODEL_INDEX = 1  # Set the best model index according to the previous results
fig2 = models[BEST_MODEL_INDEX].plot_components(forecast)

定價數據中年度趨勢圖表的螢幕快照。

在這些圖表中,淺藍色陰影會反映不確定性。 頂端圖表顯示強式長期振蕩趨勢。 幾年來,銷售量上升和下降。 較低的圖表顯示,2月和9月的銷售量趨於峰值,達到當月當年的最大值。 在那些月之後不久,在3月和10月,它們跌至該年度的最小值。

使用各種計量評估模型的效能,例如:

  • 平均平方誤差 (MSE)
  • 根均平方誤差 (RMSE)
  • 平均絕對誤差 (MAE)
  • 平均絕對百分比誤差 (MAPE)
  • 中位數絕對百分比誤差 (MDAPE)
  • 對稱平均絕對百分比誤差 (SMAPE)

使用 yhat_loweryhat_upper 估計來評估涵蓋範圍。 請注意您未來預測一年、12 次的不同地平線。

display(df_metrics[BEST_MODEL_INDEX])

透過MAPE計量,針對此預測模型,將一個月延長至未來的預測通常涉及大約8%的錯誤。 不過,對於未來一年的預測,誤差會增加到大約10%。

步驟 5:為模型評分並儲存預測結果

現在為模型評分,並儲存預測結果。

使用 Predict Transformer 進行預測

現在,您可以載入模型,並用它來進行預測。 使用者可以使用 PREDICT 來運作機器學習模型,這是可調整的 Microsoft Fabric 函式,可在任何計算引擎中支援批次評分。 在此PREDICT資源中深入瞭解 ,以及如何在 Microsoft Fabric 內使用它。

from synapse.ml.predict import MLFlowTransformer

spark.conf.set("spark.synapse.ml.predict.enabled", "true")

model = MLFlowTransformer(
    inputCols=future.columns.values,
    outputCol="prediction",
    modelName=f"{EXPERIMENT_NAME}-prophet",
    modelVersion=BEST_MODEL_INDEX,
)

test_spark = spark.createDataFrame(data=future, schema=future.columns.to_list())

batch_predictions = model.transform(test_spark)

display(batch_predictions)
# Code for saving predictions into lakehouse
batch_predictions.write.format("delta").mode("overwrite").save(
    f"{DATA_FOLDER}/predictions/batch_predictions"
)
# Determine the entire runtime
print(f"Full run cost {int(time.time() - ts)} seconds.")