Time series prediction using Prophet in Python
By: Renu Khandelwal
Tags: Holidays, Time Series Forecasting, Data Science, Multivariate Regression, Prophet

In this post we will explore facebook’s time series model Prophet. We will understand what is prophet and it’s advantages. We explore Prophet using a dataset to understand change points, how to include holidays and finally using multiple regressors for time series prediction.

What is Prophet?

Prophet is a facebooks’ open source time series prediction. Prophet decomposes time series into trend, seasonality and holiday. It has intuitive hyper parameters which are easy to tune.

Prophet time series = Trend + Seasonality + Holiday + error

Trend models non periodic changes in the value of the time series.

Seasonality is the periodic changes like daily, weekly, or yearly seasonality.

Holiday effect which occur on irregular schedules over a day or a period of days.

Error terms is what is not explained by the model.

Advantages of using Prophet

Accommodates seasonality with multiple periods

Prophet is resilient to missing values

Best way to handle outliers in Prophet is to remove them

Fitting of the model is fast

Intuitive hyper parameters which are easy to tune

Installing Prophet

Install Prophet using either command prompt or Anaconda prompt using pip

pip install fbprophet

We can also install plotly for plotting the data for prophet

pip install plotly

Create the input data for Prophet

Input to Prophet is a dataframe with minimum two columns : ds and y.

ds is datestamp column and should be as per pandas datatime format, YYYY-MM-DD or YYYY-MM-DD HH:MM:SS for a timestamp.

y is the numeric column we want to predict or forecast.

Prophet follows sklearn model API of creating an instance of the Prophet, fitting the data on Prophet object and then predict the future values.

We now dive in right into the code and look at change points, how to include holidays and then add multiple regressors.

Avocado data set is used in the article

Importing the required libraries

from fbprophet import Prophet

from fbprophet.plot import plot_plotly

import numpy as np

import pandas as pd import matplotlib.pyplot as plt

import plotly.offline as py

py.init_notebook_mode()

%matplotlib inline

Reading the data from the csv file

dataset= pd.read_csv(“C:\\avocado-prices\\avocado.csv”)

Understanding the data

Let’s first look at the columns and the data

dataset.head(2)

Let’s print the information about the dataset that includes columns, data type of the columns and if the column is null or not null

dataset.info()

We see two categorical variables, type and region. Let’s examine them

dataset.describe(include=’O’)

Converting categorical variable to numeric using LabelEncoder

We convert categorical variable, type which has two distinct values to numeric value.To convert categorical variable to numeric value we use LabelEncoder. We are not converting categorical variable, region for this example.

from sklearn.preprocessing import LabelEncoder le = LabelEncoder()

dataset.iloc[:,10] = le.fit_transform(dataset.iloc[:,10])

dataset.head(2)

type is now converted to numeric

Creating input features(X) and target variable(y)

X= dataset[['Date',‘Total Volume’, ‘4046’, ‘4225’, ‘4770’,

‘Small Bags’, ‘Large Bags’, ‘XLarge Bags’, ‘type’]]

y= dataset.iloc[:,1]

Creating the data set for Prophet

As mentioned earlier, input to Prophet is a data frame with minimum two columns : ds and y

train_dataset= pd.DataFrame()

train_dataset['ds'] = pd.to_datetime(X["Date"])

train_dataset['y']=y

train_dataset.head(2)

Creating and fitting the Prophet model with default values

We will first explore the default Prophet model. Create the Prophet instance with all default values, fit the dataset.

prophet_basic = Prophet()

prophet_basic.fit(train_dataset)

Predicting the values for the future

For predicting the values using Prophet, we need to create a dataframe with ds(datetime stamp) containing the dates for which we want to make the predictions.

We use make_future_dataframe() to which we specify the number of days to extend into the future. By default it includes dates from the history

future= prophet_basic.make_future_dataframe(periods=300)

future.tail(2)

Total number of rows in original dataset was 18249 and we see that the future data frame that we created for prediction contains historical dates as well as additional 300 dates.

forecast=prophet_basic.predict(future)

Plotting the predicted data

fig1 =prophet_basic.plot(forecast)

Plotting the forecasted components

We can plot the trend and seasonality, components of the forecast.

fig1 = prophet_basic.plot_components(forecast)

Components of the forecast

Adding ChangePoints to Prophet

Changepoints are the datetime points where the time series have abrupt changes in the trajectory.

By default, Prophet adds 25 changepoints to the initial 80% of the data-set.

Let’s plot the vertical lines where the potential changepoints occurred

from fbprophet.plot import add_changepoints_to_plot fig = prophet_basic.plot(forecast)

a = add_changepoints_to_plot(fig.gca(), prophet_basic, forecast)

Vertical lines are where changepoints occurred

We can view the dates where the chagepoints occurred

prophet_basic.changepoints

We can change the inferred changepoint range by setting the changepoint_range

pro_change= Prophet(changepoint_range=0.9) forecast = pro_change.fit(train_dataset).predict(future)

fig= pro_change.plot(forecast);

a = add_changepoints_to_plot(fig.gca(), pro_change, forecast)

The number of changepoints can be set by using the n_changepoints parameter when initializing prophet

pro_change= Prophet(n_changepoints=20, yearly_seasonality=True) forecast = pro_change.fit(train_dataset).predict(future)

fig= pro_change.plot(forecast);

a = add_changepoints_to_plot(fig.gca(), pro_change, forecast)

Adjusting Trend

Prophet allow you to adjust the trend in case there is an overfit or underfit. changepoint_prior_scale helps adjust the strength of the trend.

Default value for changepoint_prior_scale is 0.05. Decrease the value to make the trend less flexible. Increase the value of changepoint_prior_scale to make the trend more flexible.

Increasing the changepoint_prior_scale to 0.08 to make the trend flexible

pro_change= Prophet(n_changepoints=20, yearly_seasonality=True, changepoint_prior_scale=0.08)

forecast = pro_change.fit(train_dataset).predict(future)

fig= pro_change.plot(forecast);

a = add_changepoints_to_plot(fig.gca(), pro_change, forecast)

Decreasing the changepoint_prior_scale to 0.001 to make the trend less flexible

pro_change= Prophet(n_changepoints=20, yearly_seasonality=True, changepoint_prior_scale=0.001)

forecast = pro_change.fit(train_dataset).predict(future)

fig= pro_change.plot(forecast);

a = add_changepoints_to_plot(fig.gca(), pro_change, forecast)

Adding Holidays

Holidays and events can cause changes to a time series. In our example the National Avocado day on July 31 and Guacamole day on September 16 can impact prices of the Avocado.

We can create a custom holiday list for Prophet by creating a dataframe with two columns ds and holiday. A row for each occurrence of the holiday

avocado_season = pd.DataFrame({

'holiday': 'avocado season',

'ds': pd.to_datetime(['2014-07-31', '2014-09-16',

'2015-07-31', '2015-09-16',

'2016-07-31', '2016-09-16',

'2017-07-31', '2017-09-16',

'2018-07-31', '2018-09-16',

'2019-07-31', '2019-09-16']),

'lower_window': -1,

'upper_window': 0,

})

lower window and upper window extend holiday to days around the date. If we want to include a day prior to the national avocado day and Guacamole day, we set lower_window: -1 upper_window: 0

If we wanted to use the day after the holiday then set lower_window: 0 upper_window: 1

pro_holiday= Prophet(holidays=avocado_season)

pro_holiday.fit(train_dataset)

future_data = pro_holiday.make_future_dataframe(periods=12, freq = 'm')



#forecast the data for future data forecast_data = pro_holiday.predict(future_data)

pro_holiday.plot(forecast_data);

Adding Multiple Regressors

Additional regressors can be added to the Prophet model. This is done by using add_regressor. Additional regressor column value needs to be present in both the fitting as well as prediction dataframes.

Creating fitting and predicting dataset with additional regressors

train_dataset[‘type’] = X[‘type’]

train_dataset[‘Total Volume’] = X[‘Total Volume’]

train_dataset[‘4046’] = X[‘4046’]

train_dataset[‘4225’] = X[‘4225’]

train_dataset[‘4770’] = X[‘4770’]

train_dataset[‘Small Bags’] = X[‘Small Bags’] train_X= train_dataset[:18000]

test_X= train_dataset[18000:]

we split our data set to demonstrate the use of the additional regressor as we need all the additional regressors values in both fitting and predicting data frames

#Additional Regressor

pro_regressor= Prophet()

pro_regressor.add_regressor('type')

pro_regressor.add_regressor('Total Volume')

pro_regressor.add_regressor('4046')

pro_regressor.add_regressor('4225')

pro_regressor.add_regressor('4770')

pro_regressor.add_regressor('Small Bags') #Fitting the data

pro_regressor.fit(train_X)

future_data = pro_regressor.make_future_dataframe(periods=249) #forecast the data for Test data

forecast_data = pro_regressor.predict(test_X)

pro_regressor.plot(forecast_data);

Prediction using additional regressor

Predicted data is the blue shaded region at the end.

Jupyter notebook available here

References:

https://facebook.github.io/prophet/docs/quick_start.html

https://peerj.com/preprints/3190.pdf