This project examines the Massachusetts housing market using seasonal time series forecasting in Python to predict fluctuations in median listing prices from 2016 to 2024. The analysis reveals a consistent pattern of periodic decreases followed by sharp increases. The guiding question for this project asked when we could expect to see a decrease in real-estate prices. The primary goal of this project was to apply data analysis techniques learned throughout the course to examine historical data and uncover patterns that could provide insights into future trends.
In order to address the question guiding my project, I needed to expand my knowledge of series and smoothing curves to data so that the curves could be extended past the dataset. To accomplish this, I needed to learn how to use a time series in a predictive model. At first, this seemed like a simple task, but then I realized that I would need to use a specific model that would capture the seasonality of the data since it has simultaneous periods of increase and decrease. There are several different models that exist that can capture this seasonality, but I ended up using the SARIMAX model. This time series forecasting technique captures the pattern of the data instead of only accounting for the overall trend and extends this pattern into the future which is accomplished by differencing the data with a seasonal frequency while using external data to calculate the predicted values.
# import packages
import pandas as pd
from datetime import datetime
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.pylab import rcParams
from statsmodels.tsa.stattools import adfuller
import pmdarima as pm
from statsmodels.tsa.seasonal import seasonal_decompose
# settings for dataframe output
pd.set_option('display.max_rows', None)
pd.set_option('display.max_columns', None)
pd.set_option('display.width', None)
pd.set_option('display.max_colwidth', None)
# read in csv and assign data to dataframe
filename = 'median housing inventory price ma.csv'
market_prices_df = pd.read_csv(filename, index_col = 0)
print(market_prices_df)
# convert date index to datetime object
market_prices_df.index = pd.to_datetime(market_prices_df.index)
# differencing
market_prices_df['MEDLISPRIMA_diff'] = market_prices_df['MEDLISPRIMA'].diff(periods=12)
market_prices_df['MEDLISPRIMA_diff'] = market_prices_df['MEDLISPRIMA_diff'].bfill()
# identify seasonal component
result = seasonal_decompose(market_prices_df['MEDLISPRIMA'], model='multiplicative', period=12)
trend = result.trend.dropna()
seasonal = result.seasonal.dropna()
residual = result.resid.dropna()
# plot the decomposed components
plt.figure(figsize=(6,6))
plt.subplot(4, 1, 1)
plt.plot(market_prices_df['MEDLISPRIMA'], label='Original Series')
plt.legend(loc = 'upper left')
plt.subplot(4, 1, 2)
plt.plot(trend, label='Trend')
plt.legend(loc = 'upper left')
plt.subplot(4, 1, 3)
plt.plot(seasonal, label='Seasonal')
plt.legend(loc = 'upper left')
plt.subplot(4, 1, 4)
plt.plot(residual, label='Residuals')
plt.legend(loc = 'upper left')
plt.tight_layout()
plt.savefig('housing_orig.png') # save fig to visualize
# exogenous variable
market_prices_df['month_index'] = market_prices_df.index.month
# sarimax model fitting
SARIMAX_model = pm.auto_arima(market_prices_df[['MEDLISPRIMA']], exogenous=market_prices_df[['month_index']],
start_p=1, start_q=1,
test='adf',
max_p=3, max_q=3, m=12,
start_P=0, seasonal=True,
d=None, D=1,
trace=False,
error_action='ignore',
suppress_warnings=True,
stepwise=True)
# sarimax forecasting
def sarimax_forecast(SARIMAX_model, periods=36): # forecasting for 36 months
# forecast
n_periods = periods
forecast_df = pd.DataFrame({"month_index": pd.date_range(market_prices_df.index[-1], periods=n_periods, freq='MS').month},
index=pd.date_range(market_prices_df.index[-1] + pd.DateOffset(months=1), periods=n_periods, freq='MS'))
fitted, confint = SARIMAX_model.predict(n_periods=n_periods, return_conf_int=True, exogenous=forecast_df[['month_index']])
index_of_fc = pd.date_range(market_prices_df.index[-1] + pd.DateOffset(months=1), periods=n_periods, freq='MS')
# make series for plotting purpose
fitted_series = pd.Series(fitted, index=index_of_fc)
lower_series = pd.Series(confint[:, 0], index=index_of_fc)
upper_series = pd.Series(confint[:, 1], index=index_of_fc)
# plot
plt.figure(figsize=(15, 7))
plt.plot(market_prices_df["MEDLISPRIMA"], color='#1f76b4')
plt.plot(fitted_series, color='darkgreen')
plt.fill_between(lower_series.index,
lower_series,
upper_series,
color='k', alpha=.15)
plt.title("Historical Housing Inventory Price with Forecasted Values")
plt.xlabel('Year')
plt.ylabel('Price (USD)')
plt.savefig('SARIMAX.png')
# forecasting
sarimax_forecast(SARIMAX_model, periods=36) # 36 = num of forecasted months
There is an upward trend between real-estate prices over time with seasonal increases and decreases. Each period usually spans across a few months with seasonal increases having a greater magnitude than the following decreases. This pattern of fluctuation captured by plotting the historical data was bale to be used to forecast future fluctuations in the market. Therefore, by extending the curve beyond the window of the data set, we can see that there will continue to be similar periods of increase and decrease with an overall upward trend. To answer the guiding question of when the housing bubble will pop, this has been predicted to occur within the 2024 calendar year with a decrease no greater than two hundred thousand dollars and no less than twenty-five thousand dollars.