In [1]:
# data analysis
import numpy as np
import pandas as pd

# data visualization
import matplotlib.pyplot as plt
import seaborn as sns

#prophet time series
from fbprophet import Prophet

Learn By Building - Time Series Forecasting using Prophet in Python¶

Sebelumnya anda sudah mempelajari metode membangun model time series untuk melakukan forecasting total quantity penjualan dari shop_id = 31. Pada LBB kali ini, silahkan buat sebuah pemodelan untuk melakukan forecasting total revenue pada shop_id = 25

Data Cleansing and Preprocessing¶

1. Read Dataframe

In [2]:
# code here
sales = pd.read_csv('data_input/sales_train.csv')
sales.head()
Out[2]:
date date_block_num shop_id item_id item_price item_cnt_day
0 02.01.2013 0 59 22154 999.00 1.0
1 03.01.2013 0 25 2552 899.00 1.0
2 05.01.2013 0 25 2552 899.00 -1.0
3 06.01.2013 0 25 2554 1709.05 1.0
4 15.01.2013 0 25 2555 1099.00 1.0

2. Transform Data Types

In [3]:
# code here
sales['date'] = pd.to_datetime(sales['date'], dayfirst=True)
sales.sort_values('date',inplace=True)

3. Create colums total_revenue based on item_price * item_cnt_day

In [4]:
# code here
sales['total_revenue'] = sales['item_price'] * sales['item_cnt_day']
sales.head()
Out[4]:
date date_block_num shop_id item_id item_price item_cnt_day total_revenue
49800 2013-01-01 0 18 5823 2500.0 1.0 2500.0
29784 2013-01-01 0 27 5573 849.0 1.0 849.0
35476 2013-01-01 0 7 1006 399.0 1.0 399.0
8330 2013-01-01 0 19 17707 899.0 1.0 899.0
57384 2013-01-01 0 14 19548 149.0 1.0 149.0

4. Select observation only from shop_id=25

In [5]:
# code here
sales_25 = sales[sales['shop_id'] == 25].reset_index(drop=True)
sales_25.head()

daily_sales = sales_25.groupby(['date', 'shop_id']) \
                ['total_revenue'] \
                .sum().reset_index()
daily_sales.head()
Out[5]:
date shop_id total_revenue
0 2013-01-02 25 345174.13
1 2013-01-03 25 249421.00
2 2013-01-04 25 233731.00
3 2013-01-05 25 226029.00
4 2013-01-06 25 273742.00

Modeling using fbprophet¶

1. Prepare dataframe contains ds and y columns

In [6]:
# code here
daily_total_rev = daily_sales[['date', 'total_revenue']].rename(
    columns={'date': 'ds',
             'total_revenue': 'y'})

daily_total_rev.head()
Out[6]:
ds y
0 2013-01-02 345174.13
1 2013-01-03 249421.00
2 2013-01-04 233731.00
3 2013-01-05 226029.00
4 2013-01-06 273742.00

2. Fitting Model

In [7]:
# code here
model_25 = Prophet()
model_25.fit(daily_total_rev)
INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[7]:
<fbprophet.forecaster.Prophet at 0x1e2c047af70>

3. Forecasting (make future dataframe and then predict)

In [8]:
# code here, 
#create future data stamp
future_25 = model_25.make_future_dataframe(periods=365, freq='D')
future_25.tail()
#forecast
forecast_25 = model_25.predict(future_25)
forecast_25.head()
forecast_25[['ds', 'trend', 'weekly', 'yearly', 'yhat']]
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[8]:
ds trend weekly yearly yhat
0 2013-01-02 199178.797187 -17330.220593 249679.725245 431528.301840
1 2013-01-03 199216.723642 -5427.689157 225342.933025 419131.967509
2 2013-01-04 199254.650096 58078.733151 199517.526853 456850.910100
3 2013-01-05 199292.576551 44090.110617 172594.625907 415977.313075
4 2013-01-06 199330.503005 -20048.450529 144982.730786 324264.783261
... ... ... ... ... ...
1390 2016-10-26 253717.273879 -17330.220593 -33826.942643 202560.110643
1391 2016-10-27 253753.473690 -5427.689157 -32397.121393 215928.663140
1392 2016-10-28 253789.673501 58078.733151 -29939.347986 281929.058666
1393 2016-10-29 253825.873312 44090.110617 -26452.106853 271463.877076
1394 2016-10-30 253862.073123 -20048.450529 -21958.524193 211855.098400

1395 rows × 5 columns

4. Visualize the model

In [9]:
# code here
fig = model_25.plot(forecast_25)
fig2 = model_25.plot_components(forecast_25)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)

Model Tuning¶

From https://www.timeanddate.com/holidays/russia/2016 we know that in 2016, New Year and Christmas Holiday happened from 1 to 10 january

And from other sources we know that Russian celebrate christmas based on orthodox calendar which is in jan, so lets assume that sales on first week of january will be the highest in a year

Country Holiday¶

In [10]:
model_holiday_rus = Prophet()
model_holiday_rus.add_country_holidays(country_name='RU')
model_holiday_rus.fit(daily_total_rev)

model_holiday_rus.train_holiday_names
INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[10]:
0                    New Year's Day
1            Orthodox Christmas Day
2                     Christmas Day
3    Defender of the Fatherland Day
4         International Women's Day
5                 National Flag Day
6             Spring and Labour Day
7                       Victory Day
8                        Russia Day
9                         Unity Day
dtype: object
In [11]:
# Reference: https://github.com/facebook/prophet/blob/master/python/fbprophet/hdays.py
from fbprophet import hdays
holidays_rus = hdays.Russia()
holidays_rus._populate(2013)
holidays_rus._populate(2014)
holidays_rus._populate(2015)
holidays_in_rus = pd.DataFrame([holidays_rus], index=['holiday']).T.rename_axis('ds').reset_index()
holidays_in_rus
Out[11]:
ds holiday
0 2013-01-01 New Year's Day
1 2013-01-07 Orthodox Christmas Day
2 2013-12-25 Christmas Day
3 2013-02-23 Defender of the Fatherland Day
4 2013-03-08 International Women's Day
5 2013-08-22 National Flag Day
6 2013-05-01 Spring and Labour Day
7 2013-05-09 Victory Day
8 2013-06-12 Russia Day
9 2013-11-04 Unity Day
10 2014-01-01 New Year's Day
11 2014-01-07 Orthodox Christmas Day
12 2014-12-25 Christmas Day
13 2014-02-23 Defender of the Fatherland Day
14 2014-03-08 International Women's Day
15 2014-08-22 National Flag Day
16 2014-05-01 Spring and Labour Day
17 2014-05-09 Victory Day
18 2014-06-12 Russia Day
19 2014-11-04 Unity Day
20 2015-01-01 New Year's Day
21 2015-01-07 Orthodox Christmas Day
22 2015-12-25 Christmas Day
23 2015-02-23 Defender of the Fatherland Day
24 2015-03-08 International Women's Day
25 2015-08-22 National Flag Day
26 2015-05-01 Spring and Labour Day
27 2015-05-09 Victory Day
28 2015-06-12 Russia Day
29 2015-11-04 Unity Day

Default Holiday¶

In [12]:
holiday = pd.DataFrame({
    'holiday': 'new_year_eve',
    'ds': pd.to_datetime(['2013-12-31', '2014-12-31', # past date, historical data 
                          '2015-12-31']), # future date, to be forecasted
    'lower_window': -4,
    'upper_window': 2})
holiday
Out[12]:
holiday ds lower_window upper_window
0 new_year_eve 2013-12-31 -4 2
1 new_year_eve 2014-12-31 -4 2
2 new_year_eve 2015-12-31 -4 2
In [13]:
# fitting model
model_holiday_rus = Prophet(holidays=holiday) #mendefinisikan hari libur
model_holiday_rus.fit(daily_total_rev) #melakukan fitting model yang sudah ditambah efek holiday

# forecasting
future = model_holiday_rus.make_future_dataframe(periods=365, freq='D') #membuat time window
forecast = model_holiday_rus.predict(future)

# visualize
fig = model_holiday_rus.plot(forecast)
INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
In [14]:
# code here
cutoff = pd.to_datetime('2015-01-01')
daily_total_rev['type'] = daily_total_rev['ds'].apply(
    lambda date: 'train' if date < cutoff else 'test')

plt.figure(figsize=(10, 5))
sns.scatterplot(x='ds', y='y', hue='type', s=7,
                palette=['black', 'red'],
                data=daily_total_rev)
plt.axvline(x=cutoff, color='gray', label='cutoff')
plt.legend()
plt.show()
In [15]:
#Split data train and test
train = daily_total_rev[daily_total_rev['ds'] < cutoff] # sebagai data yang akan dilatih
test = daily_total_rev[daily_total_rev['ds'] >= cutoff] # data unseen (dari visualisasi titik2 berwarna merah)
In [16]:
# fitting model
model_final = Prophet(
    holidays=holiday, # holiday effect
    yearly_seasonality=True)
model_final.add_seasonality(name='monthly', period=30.5, fourier_order=5) # add monthly seasonality
model_final.fit(train)
INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[16]:
<fbprophet.forecaster.Prophet at 0x1e2c86ca8e0>
In [17]:
# forecasting
future_final = model_final.make_future_dataframe(periods=303, freq='D') # 303 days (test size) -> adalah data dari 01 Jan 2015 - 31 Oct 2015
forecast_final = model_final.predict(future_final) #melakukan prediksi terhadap data test
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
In [18]:
# visualize
fig = model_final.plot(forecast_final)
plt.scatter(x=test['ds'], y=test['y'], s=10, color='red')
plt.show()

Evaluation¶

In [19]:
forecast_final
Out[19]:
ds trend yhat_lower yhat_upper trend_lower trend_upper additive_terms additive_terms_lower additive_terms_upper holidays ... weekly weekly_lower weekly_upper yearly yearly_lower yearly_upper multiplicative_terms multiplicative_terms_lower multiplicative_terms_upper yhat
0 2013-01-02 200710.113233 159544.390872 439166.253265 200710.113233 200710.113233 93869.855975 93869.855975 93869.855975 0.0 ... -25746.192468 -25746.192468 -25746.192468 146986.533130 146986.533130 146986.533130 0.0 0.0 0.0 294579.969208
1 2013-01-03 200711.892320 177430.414550 460650.754638 200711.892320 200711.892320 118412.718670 118412.718670 118412.718670 0.0 ... 1412.629911 1412.629911 1412.629911 128432.507781 128432.507781 128432.507781 0.0 0.0 0.0 319124.610990
2 2013-01-04 200713.671408 242443.695592 520332.932116 200713.671408 200713.671408 182880.557782 182880.557782 182880.557782 0.0 ... 70262.534906 70262.534906 70262.534906 109191.922855 109191.922855 109191.922855 0.0 0.0 0.0 383594.229190
3 2013-01-05 200715.450496 201573.626034 492343.390714 200715.450496 200715.450496 144617.560807 144617.560807 144617.560807 0.0 ... 52111.003842 52111.003842 52111.003842 89538.626704 89538.626704 89538.626704 0.0 0.0 0.0 345333.011303
4 2013-01-06 200717.229584 95779.117010 396231.047434 200717.229584 200717.229584 39657.506769 39657.506769 39657.506769 0.0 ... -16055.652766 -16055.652766 -16055.652766 69754.070794 69754.070794 69754.070794 0.0 0.0 0.0 240374.736352
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
1025 2015-10-26 319932.874431 68761.750127 356536.511838 311170.434958 329613.333953 -101357.944788 -101357.944788 -101357.944788 0.0 ... -64360.671926 -64360.671926 -64360.671926 -44928.963535 -44928.963535 -44928.963535 0.0 0.0 0.0 218574.929644
1026 2015-10-27 320167.514542 129000.961216 417840.494772 311358.987281 329888.962484 -46769.432747 -46769.432747 -46769.432747 0.0 ... -17623.651498 -17623.651498 -17623.651498 -43296.649531 -43296.649531 -43296.649531 0.0 0.0 0.0 273398.081795
1027 2015-10-28 320402.154652 129561.626035 413401.917144 311550.348173 330120.512407 -49457.413042 -49457.413042 -49457.413042 0.0 ... -25746.192468 -25746.192468 -25746.192468 -40749.322044 -40749.322044 -40749.322044 0.0 0.0 0.0 270944.741610
1028 2015-10-29 320636.794762 163704.260401 454564.363276 311741.709066 330375.940709 -15231.671485 -15231.671485 -15231.671485 0.0 ... 1412.629911 1412.629911 1412.629911 -37309.302126 -37309.302126 -37309.302126 0.0 0.0 0.0 305405.123277
1029 2015-10-30 320871.434873 251537.159781 521413.038031 311933.130302 330669.675554 64817.293504 64817.293504 64817.293504 0.0 ... 70262.534906 70262.534906 70262.534906 -33015.339470 -33015.339470 -33015.339470 0.0 0.0 0.0 385688.728377

1030 rows × 28 columns

Data Train Error Check

In [20]:
from sklearn.metrics import mean_absolute_percentage_error

forecast_train = forecast_final[forecast_final['ds'] < cutoff]
forecast_train.head(2)
Out[20]:
ds trend yhat_lower yhat_upper trend_lower trend_upper additive_terms additive_terms_lower additive_terms_upper holidays ... weekly weekly_lower weekly_upper yearly yearly_lower yearly_upper multiplicative_terms multiplicative_terms_lower multiplicative_terms_upper yhat
0 2013-01-02 200710.113233 159544.390872 439166.253265 200710.113233 200710.113233 93869.855975 93869.855975 93869.855975 0.0 ... -25746.192468 -25746.192468 -25746.192468 146986.533130 146986.533130 146986.533130 0.0 0.0 0.0 294579.969208
1 2013-01-03 200711.892320 177430.414550 460650.754638 200711.892320 200711.892320 118412.718670 118412.718670 118412.718670 0.0 ... 1412.629911 1412.629911 1412.629911 128432.507781 128432.507781 128432.507781 0.0 0.0 0.0 319124.610990

2 rows × 28 columns

In [21]:
train_mape = mean_absolute_percentage_error(y_true=train['y'],
                                     y_pred=forecast_train['yhat'])
train_mape
Out[21]:
0.28916917808618675
In [22]:
forecast_test = forecast_final[forecast_final['ds'] >= cutoff]
forecast_test.head(2)
Out[22]:
ds trend yhat_lower yhat_upper trend_lower trend_upper additive_terms additive_terms_lower additive_terms_upper holidays ... weekly weekly_lower weekly_upper yearly yearly_lower yearly_upper multiplicative_terms multiplicative_terms_lower multiplicative_terms_upper yhat
727 2015-01-01 250010.121569 290410.725629 586052.969610 250010.121569 250010.121569 185760.562061 185760.562061 185760.562061 0.000000 ... 1412.629911 1412.629911 1412.629911 172964.931424 172964.931424 172964.931424 0.0 0.0 0.0 435770.683630
728 2015-01-02 250244.761679 444267.420113 743255.110827 250244.761679 250244.761679 338119.946656 338119.946656 338119.946656 124810.279493 ... 70262.534906 70262.534906 70262.534906 155923.962280 155923.962280 155923.962280 0.0 0.0 0.0 588364.708335

2 rows × 28 columns

In [23]:
test_mape = mean_absolute_percentage_error(y_true=test['y'],
                                     y_pred=forecast_test['yhat'])
test_mape
Out[23]:
0.628312821856566

From the results, it shows MAPE train around 29% and MAPE test around 62% which is still quite high (or bad), i think it would be a good move if we do some further tuning.

Cross Validation¶

In [24]:
from fbprophet.diagnostics import cross_validation
df_cv = cross_validation(model_holiday_rus, initial='730 days', horizon='30 days', period='30 days')
df_cv
INFO:fbprophet:Making 10 forecasts with cutoffs between 2015-01-04 00:00:00 and 2015-10-01 00:00:00
  0%|          | 0/10 [00:00<?, ?it/s]
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[24]:
ds yhat yhat_lower yhat_upper y cutoff
0 2015-01-05 277273.606118 123774.740251 429203.199141 278645.0 2015-01-04
1 2015-01-06 304872.670027 159370.309259 461263.674692 374783.0 2015-01-04
2 2015-01-07 277966.463613 125673.781198 418014.074614 379984.0 2015-01-04
3 2015-01-08 287155.520617 130743.109009 434251.577257 246544.0 2015-01-04
4 2015-01-09 337318.494772 193685.340452 494637.861828 179392.0 2015-01-04
... ... ... ... ... ... ...
295 2015-10-27 180436.148546 38014.164687 328267.257597 165969.0 2015-10-01
296 2015-10-28 173437.885441 26538.156867 329265.695606 152358.0 2015-10-01
297 2015-10-29 193397.588758 45595.599011 341486.552059 179331.0 2015-10-01
298 2015-10-30 258019.158325 119015.294253 401467.339379 297992.0 2015-10-01
299 2015-10-31 247615.018131 102240.127561 400110.030775 263524.0 2015-10-01

300 rows × 6 columns

In [25]:
cv_mape = df_cv.groupby('cutoff').apply(
    lambda x: mean_absolute_percentage_error(y_true=x['y'],
                                     y_pred=x['yhat']))
cv_mape
Out[25]:
cutoff
2015-01-04    0.348856
2015-02-03    0.534362
2015-03-05    0.446446
2015-04-04    0.251898
2015-05-04    0.321683
2015-06-03    0.431438
2015-07-03    0.413404
2015-08-02    0.433229
2015-09-01    0.337201
2015-10-01    0.359264
dtype: float64
In [26]:
cv_mape.mean()
Out[26]:
0.3877780779789091

Hyperparameter Tuning¶

In [71]:
model_tune1 = Prophet(
    holidays=holiday,
    changepoint_prior_scale=0.1,
    changepoint_range=0.1
)
model_tune1.fit(daily_total_rev)
INFO:fbprophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[71]:
<fbprophet.forecaster.Prophet at 0x1e2c8b539a0>
In [72]:
cv_tune = cross_validation(model_tune1, initial='730 days', horizon = '30 days', period='90 days')
cv_tune
INFO:fbprophet:Making 4 forecasts with cutoffs between 2015-01-04 00:00:00 and 2015-10-01 00:00:00
  0%|          | 0/4 [00:00<?, ?it/s]
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[72]:
ds yhat yhat_lower yhat_upper y cutoff
0 2015-01-05 256965.221479 111260.734398 407517.979462 278645.0 2015-01-04
1 2015-01-06 284292.047495 134660.725996 438087.468561 374783.0 2015-01-04
2 2015-01-07 257241.237028 110800.242655 399841.921851 379984.0 2015-01-04
3 2015-01-08 265811.711955 111569.737880 412561.605429 246544.0 2015-01-04
4 2015-01-09 315778.623855 155248.642871 461223.556155 179392.0 2015-01-04
... ... ... ... ... ... ...
115 2015-10-27 182179.276224 33725.367763 329023.691389 165969.0 2015-10-01
116 2015-10-28 175254.544371 29178.502418 319402.342022 152358.0 2015-10-01
117 2015-10-29 195176.525547 46228.290707 351200.136256 179331.0 2015-10-01
118 2015-10-30 259827.242967 100761.109709 412488.325063 297992.0 2015-10-01
119 2015-10-31 249401.077876 98791.580863 399140.691847 263524.0 2015-10-01

120 rows × 6 columns

In [73]:
cv_mape_tune = cv_tune.groupby('cutoff').apply(
    lambda x: mean_absolute_percentage_error(y_true=x['y'],
                                     y_pred=x['yhat']))
cv_mape_tune
Out[73]:
cutoff
2015-01-04    0.310511
2015-04-04    0.252755
2015-07-03    0.370609
2015-10-01    0.362798
dtype: float64
In [74]:
cv_mape_tune.mean()
Out[74]:
0.32416795056509945
In [75]:
# code here
future_tune = model_tune1.make_future_dataframe(periods=365, freq='D')
forecast_tune = model_tune1.predict(future_tune)

model_tune1.plot(forecast_tune)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
C:\Users\USER\anaconda3\envs\dss-prophet\lib\site-packages\fbprophet\forecaster.py:891: FutureWarning: The frame.append method is deprecated and will be removed from pandas in a future version. Use pandas.concat instead.
  components = components.append(new_comp)
Out[75]:

Conclusion¶

I chose Default Holiday as first tuning because it can give lower MAPE result.

On Cross Validation Method and by implementing Hyperparameter Tuning, i use changepoint_prior_scale and changepoint_range as mentioned to get a lowest MAPE mean result. The result is (CV_MAPE_TUNE) 32.4% still quite high, i might choose additional method to lower the error.