Träna och utvärdera en tidsserieprognosmodell i Microsoft Fabric
I den här notebook-filen ska vi utveckla ett program för att prognostisera tidsseriedata som har säsongscykler. Vi använder datauppsättningen NYC Property Sales med datum från 2003 till 2015 som publicerats av NYC Department of Finance på NYC Open Data Portal.
Viktigt
Microsoft Fabric är för närvarande i förhandsversion. Den här informationen gäller en förhandsversionsprodukt som kan ändras avsevärt innan den släpps. Microsoft lämnar inga garantier, uttryckta eller underförstådda, med avseende på den information som tillhandahålls här.
Datamängden är ett register över varje byggnad som säljs på New York Citys fastighetsmarknad under 13-årsperioden. Se Ordlista med villkor för egenskapsförsäljningsfiler för definition av kolumner i kalkylbladet. Datauppsättningen ser ut som i följande tabell:
Borough | Kvarter | building_class_category | tax_class | blockera | Mycket | Easement | building_class_at_present | adress | 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 | ALFABETSSTAD | 07 LÄGENHETER - WALKUP LÄGENHETER | 0.0 | 384.0 | 17,0 | C4 | 225 EAST 2ND STREET | 10009.0 | 10,0 | 0.0 | 10,0 | 2145.0 | 6670.0 | 1900.0 | 2.0 | C4 | 275000.0 | 2007-06-19 | ||
Manhattan | ALFABETSSTAD | 07 LÄGENHETER - WALKUP LÄGENHETER | 2.0 | 405.0 | 12.0 | C7 | 508 EAST 12TH STREET | 10009.0 | 28.0 | 2.0 | 30,0 | 3872.0 | 15428.0 | 1930.0 | 2.0 | C7 | 7794005.0 | 2007-05-21 |
Vi bygger upp en modell för att prognostisera månatlig volym av fastighetshandel baserat på historikdata. För att göra prognoser använder vi Facebook Prophet, som tillhandahåller snabba och automatiserade prognosprocedurer och hanterar säsongsvariationer väl.
Installera Prophet
Nu ska vi först installera Facebook Prophet. Facebook Prophet (Prophet) är ett öppen källkod tidsseriebibliotek som utvecklats av Facebook. Den använder en sönderdefinierbar tidsseriemodell som består av tre huvudkomponenter: trend, säsongsvariation och helgdagar.
För trendkomponenten förutsätter Profeten en styckevis konstant tillväxthastighet med automatiskt val av ändringspunkt.
För säsongsvariationer modellerar Prophet vecko- och års säsongsvariationer med fourier-serien. Eftersom vi använder månadsdata har vi därför ingen säsongsvariation varje vecka och överväger inte helgdagar.
!pip install prophet
Steg 1: Läs in data
Ladda ned datauppsättning och ladda upp till ett Data Lakehouse
Ett Data Lakehouse (lakehouse) är en dataarkitektur som tillhandahåller en central lagringsplats för dina data. Det finns 15 csv-filer som innehåller fastighetsförsäljningsposter från fem stadsdelar i New York sedan 2003 till 2015. För din bekvämlighet komprimeras dessa filer i nyc_property_sales.tar
och är tillgängliga i en offentlig bloblagring.
URL = "https://synapseaisolutionsa.blob.core.windows.net/public/NYC_Property_Sales_Dataset/"
TAR_FILE_NAME = "nyc_property_sales.tar"
DATA_FOLER = "Files/NYC_Property_Sales_Dataset"
TAR_FILE_PATH = f"/lakehouse/default/{DATA_FOLER}/tar/"
CSV_FILE_PATH = f"/lakehouse/default/{DATA_FOLER}/csv/"
import os
if not os.path.exists("/lakehouse/default"):
# ask user to add a lakehouse if no default lakehouse added to the notebook.
# 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:
# check if the needed files are already in the lakehouse, try to download and unzip if not.
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}")
Skapa dataram från Lakehouse
Funktionen display
skriver ut dataramen och ger automatiskt diagramvyer.
df = (
spark.read.format("csv")
.option("header", "true")
.load("Files/NYC_Property_Sales_Dataset/csv")
)
display(df)
Steg 2: Förbearbetning av data
Typkonvertering och filtrering
Låter göra några nödvändiga typkonvertering och filtrering.
- Behöver konvertera försäljningspriser till heltal.
- Du behöver undanta oregelbundna försäljningsdata. Till exempel anger en försäljning på 0 USD ägarskapsöverföring utan kontant hänsyn.
- Undanta andra byggtyper än A-klass.
Anledningen till att endast välja marknad för A-klassbyggnad för analys är att säsongseffekten inte är berättigandekoefficient för A-klassbyggnad. Modellen vi använder överträffar många andra i att inkludera säsongsvariationer, vilket är vanliga behov i tidsserieanalys.
# import libs
import pyspark.sql.functions as F
from pyspark.sql.types import *
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%"'
)
monthly_sale_df = df.select(
"sale_price",
"total_units",
"gross_square_feet",
F.date_format("sale_date", "yyyy-MM").alias("month"),
)
display(df)
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)
Visualisering
Ta nu en titt på trenden för fastighetshandelstrend på NYC. Den årliga säsongsvariationen är tydlig i den valda byggnadsklassen. De högsta köpsäsongerna är vanligtvis vår och höst.
df_pandas = summary_df.toPandas()
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()
Steg 3: Modellträning och utvärdering
Modellanpassning
Om du vill utföra modellanpassning byter du namn på tidsaxeln till "ds" och värdeaxeln till "y".
import pandas as pd
df_pandas["ds"] = pd.to_datetime(df_pandas["month"])
df_pandas["y"] = df_pandas["total_sales"]
Nu ska vi passa modellen. Vi väljer att använda "multiplicativ" säsongsvariation, det innebär att säsongsvariation inte längre är en konstant additiv faktor som standard som antas av Profeten. Som du ser i en tidigare cell skrev vi ut de totala fastighetsförsäljningsdata per månad och vibrationsamplituden är inte konsekvent. Det innebär att användning av enkla tillsatsers säsongsvariationer inte passar data bra. Dessutom använder vi Markov Chain Monte Carlo (MCMC) som ger medelvärdet av posteriori-distribution. Som standard använder Prophet Stans L-BFGS för att passa modellen, som hittar en maximal uppskattning av posteriori-sannolikhet (MAP).
from prophet import Prophet
from prophet.plot import add_changepoints_to_plot
m = Prophet(
seasonality_mode="multiplicative", weekly_seasonality=False, mcmc_samples=1000
)
m.fit(df_pandas)
Nu ska vi använda inbyggda funktioner i Prophet för att visa modellanpassningsresultatet. De svarta punkterna är datapunkter som används för att träna modellen. Den blå linjen är förutsägelsen och det ljusblå området visar osäkerhetsintervall.
future = m.make_future_dataframe(periods=12, freq="M")
forecast = m.predict(future)
fig = m.plot(forecast)
Profeten förutsätter bitvis konstant tillväxt, så du kan rita ändringspunkterna i den tränade modellen.
fig = m.plot(forecast)
a = add_changepoints_to_plot(fig.gca(), m, forecast)
Visualisera trend och årlig säsongsvariation. Det ljusblå området speglar osäkerheten.
fig2 = m.plot_components(forecast)
Korsvalidering
Vi kan använda Profetens inbyggda korsvalideringsfunktion för att mäta prognosfelet på historiska data. Följande parametrar innebär att vi bör börja med 11 års träningsdata och sedan göra förutsägelser var 30:e dag inom ett års horisont.
from prophet.diagnostics import cross_validation
from prophet.diagnostics import performance_metrics
df_cv = cross_validation(m, initial="11 Y", period="30 days", horizon="365 days")
df_p = performance_metrics(df_cv, monthly=True)
display(df_p)
Steg 4: Logga och läsa in modell med MLflow
Nu kan vi lagra den tränade modellen för senare användning.
# setup mlflow
import mlflow
EXPERIMENT_NAME = "aisample-timeseries"
mlflow.set_experiment(EXPERIMENT_NAME)
# log the model and parameters
model_name = f"{EXPERIMENT_NAME}-prophet"
with mlflow.start_run() as run:
mlflow.prophet.log_model(m, model_name, registered_model_name=model_name)
mlflow.log_params({"seasonality_mode": "multiplicative", "mcmc_samples": 1000})
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}")
# load the model back
loaded_model = mlflow.prophet.load_model(model_uri)