Time Series Forecasting#

Summary#

Using all recorded annual temperatures averages (from 1850 to 2020), I use Prophet to forecast annual temperatures for the next two decades.

Data Source#

Average northern hemisphere temperature data was obtained from https://www.metoffice.gov.uk/hadobs/hadcrut5/, specifically the “HadCRUT5 analysis time series: ensemble means and uncertainties”. The temperatures are expressed as deviations, or anomalies, from reference temperatures over the period of 1961–1990; for details see here. Each anomaly is a best estimate calculated from an ensemble of 100 time series, hence confidence intervals are present in the dataset. For the purposes of this analysis, I will just use the point estimate.

Data Exploration#

Let’s load in the data and examine it:

Note

You can run and modify the code on this page Jupyter Notebook style, but without leaving the page! Hover over the launch button at the top of the page, then click the Live Code button. If you prefer a Jupyter environment, use the Binder button instead.

You’ll need to run the following cell manually because Live Code sessions assume a cwd of the root directory. Refresh the page to revert to the original view.

import os

try:
    os.chdir("./website/stat-ml/")
except FileNotFoundError:
    pass
print(f"cwd: {os.getcwd()}")
cwd: /home/adam/projects/website/website/stat-ml
import matplotlib.pyplot as plt
import pandas as pd

df = pd.read_csv("./globwarm.csv")
df.head(3)
Time Anomaly (deg C) Lower confidence limit (2.5%) Upper confidence limit (97.5%)
0 1850 -0.435791 -0.635680 -0.235902
1 1851 -0.219249 -0.428398 -0.010100
2 1852 -0.235702 -0.457689 -0.013715
df.tail(3)
Time Anomaly (deg C) Lower confidence limit (2.5%) Upper confidence limit (97.5%)
169 2019 1.143743 1.108290 1.179197
170 2020 1.275727 1.236863 1.314590
171 2021 1.004906 0.764207 1.245604

Since 2021 data collection is still ongoing, the confidence limits are much wider. For simplicity, I’ll drop this point from the analysis.

df = df[df.Time <= 2020]

Next, let’s plot the data:

fig, ax = plt.subplots()
ax.plot(df.Time, df["Anomaly (deg C)"], "o")
ax.set(xlabel="Year", ylabel="Temperature (C)")
plt.show()
../_images/forecast_9_0.png

There is also clearly a nonlinear trend amidst the random variation from year to year. We also expect some long term cyclical patterns, for instance Milankovitch cycles due to variations in Earth’s movement relative to the Sun. However, these patterns are difficult to extract because we have just under 200 years of data to work with. These cyclical patterns are very important, however, because we don’t have access to more granular data with daily, weekly, and/or yearly variation typically present in business problems. For this reason, Prophet is useful as it can easily implement custom seasonalities. It’s also flexible in its ability to detect changepoints, another crucial parameter affecting model fit as we will see next.

Building a Simple Forecast#

First, we must format the data appropriately. Prophet expects a two column dataframe with datestamps ds formatted like YYYY-MM-DD and numeric data y.

def format_years(years):
    """Convert numeric years to YYYY-MM-DD format, using an arbitrary day."""
    ds = [str(year) + "-12-31" for year in years]
    return ds


df = df[["Time", "Anomaly (deg C)"]].rename(
    columns={"Time": "ds", "Anomaly (deg C)": "y"}
)
df.ds = format_years(df.ds)
df.head(3)
ds y
0 1850-12-31 -0.435791
1 1851-12-31 -0.219249
2 1852-12-31 -0.235702
df.tail(3)
ds y
168 2018-12-31 0.959662
169 2019-12-31 1.143743
170 2020-12-31 1.275727

df is now ready for Prophet modeling, but as hinted in § Data Exploration, a model built from defaults performs very poorly:

from prophet import Prophet


def plot_model_fit(model, df):
    """Fit and plot predictions of a Prophet() model on the training data."""
    model.fit(df)
    predictions = model.predict()
    model.plot(predictions, xlabel="Year", ylabel="Temperature (C)")


model = Prophet()
plot_model_fit(model, df)
Importing plotly failed. Interactive plots will not work.
INFO:prophet:Disabling weekly seasonality. Run prophet with weekly_seasonality=True to override this.
INFO:prophet:Disabling daily seasonality. Run prophet with daily_seasonality=True to override this.
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -17.5035
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      99       217.559   0.000640947       66.6814           1           1      128   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     188       218.511    0.00158703       88.0943   2.803e-05       0.001      286  LS failed, Hessian reset 
     199       218.616   5.91156e-05       56.8093     0.07449           1      306   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     292       218.705   2.68884e-05       64.9809   3.837e-07       0.001      470  LS failed, Hessian reset 
     299       218.705   5.18845e-06       67.2586           1           1      478   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     334       218.706   2.36909e-06        77.496   3.097e-08       0.001      563  LS failed, Hessian reset 
     342       218.706   1.90175e-09       66.7851     0.03287     0.03287      575   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
../_images/forecast_14_5.png

The reason is that we need to account for long term cycles over many years. A yearly seasonality is meaningless in this context, because we don’t have sub-year level data. Let’s try again, disabling the usual seasonalities and implementing our own using the add_seasonality() method. From the scatterplot of the raw data, any noticeable variation occurs after at least 50 years. At this scale, the variation is relatively small, so the fit shouldn’t be too flexible. In other words, we shouldn’t include too many Fourier terms, controlled by the fourier_order parameter.

model = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False,
)
model.add_seasonality("50 years", period=365 * 50, fourier_order=2)
plot_model_fit(model, df)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -17.5035
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      53       218.827     0.0054749       100.245   5.445e-05       0.001       94  LS failed, Hessian reset 
      86       219.303   0.000428905       65.8946   5.252e-06       0.001      191  LS failed, Hessian reset 
      99       219.314   7.47284e-06       41.2342      0.5794      0.5794      211   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     160       219.835   0.000219902       48.0568   4.058e-06       0.001      343  LS failed, Hessian reset 
     193       219.863   0.000114599       67.8428   1.766e-06       0.001      422  LS failed, Hessian reset 
     199       219.865    2.8985e-06       48.9324      0.2933      0.2933      429   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     219       219.866   1.76065e-06         49.44   3.818e-08       0.001      492  LS failed, Hessian reset 
     234       219.866   9.82303e-09        50.957     0.09921     0.09921      514   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
../_images/forecast_16_2.png

The fit’s a bit better in terms of smoothness, but still not great. Increasing fourier_order just amounts to more more variation around a similar mean trend line. Let’s try increasing the seasonality period a bit more:

model = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False,
)
model.add_seasonality("centuryly", period=365 * 100, fourier_order=2)
plot_model_fit(model, df)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -17.5035
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      95       248.116   5.36108e-05       42.8226   8.505e-07       0.001      168  LS failed, Hessian reset 
      99       248.117   5.87883e-06       49.9379      0.8928     0.08928      175   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     158       248.125   4.68896e-07        57.519   8.193e-09       0.001      306  LS failed, Hessian reset 
     163       248.125   8.11851e-09       51.7867      0.1544      0.1544      312   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
../_images/forecast_18_2.png

The fit is much better. Let’s see what it forecasts.

future = model.make_future_dataframe(periods=30, freq="Y")
forecast = model.predict(future)
model.plot(forecast, xlabel="Year", ylabel="Temperature (C)")
plt.show()
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
../_images/forecast_20_1.png

The model stays roughly linear with the latest data, but levels off due to the seasonality built into the model.

Optimizing the Forecast#

The previous hand-tuning was insightful, but largely experimental. A more principled approach tunes the parameters based on some performance metric(s). Cross-validation is often used for this, but we have to be a bit careful with time series data due to correlations between data points. One approach preserves the ordering of time by training on the first (say) 100 years of data and testing on the next 20 years of data. Then we train on the first 110 years of data and again test on the next 20 years of data. We repeat this until we reach the end of the data. Each batch gives us an estimate of errors of predictions made 1, 2, …, 20 years in the future while preserving the ordering of time. This approach can be implemented in Prophet as follows:

from prophet.diagnostics import cross_validation

df_cv = cross_validation(model, initial="36500 days", horizon="7300 days")
df_cv.head(3)
INFO:prophet:Making 6 forecasts with cutoffs between 1951-01-18 00:00:00 and 2001-01-05 00:00:00
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -5.25924
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      75       127.229   9.68385e-10       101.584     0.09599     0.09599       96   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -5.36242
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      99       139.461   9.76843e-05       103.123      0.7929      0.7929      120   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     143       139.524   4.58751e-05       102.166   4.693e-07       0.001      204  LS failed, Hessian reset 
     168       139.527    7.1662e-09       100.937      0.1476      0.1476      239   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -5.73025
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      99       153.794   3.71888e-06       105.159       0.349           1      126   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     138       153.795   7.36488e-09       106.455      0.4683      0.4683      176   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -6.64014
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      82       164.752   0.000308592       101.842   3.108e-06       0.001      141  LS failed, Hessian reset 
      99       164.769   1.70261e-06       99.5116      0.5224      0.5224      162   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     117       164.769   8.94213e-09       99.2085       0.177       0.177      184   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -14.1508
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      88       163.574      0.001071       107.114   9.956e-06       0.001      160  LS failed, Hessian reset 
      99       163.666   0.000165312       102.358      0.9734      0.9734      172   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     182       163.726   6.51677e-09       95.6481      0.2608      0.2608      276   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -12.6326
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      99       151.557   4.53253e-06       54.8127      0.5863      0.5863      139   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     174       151.578   5.73067e-05       84.3149   7.726e-07       0.001      277  LS failed, Hessian reset 
     199        151.58   2.07059e-07       47.3968      0.3915      0.3915      310   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     232        151.58   6.29633e-09       67.7881      0.2082           1      358   
Optimization terminated normally: 
  Convergence detected: absolute parameter change was below tolerance
ds yhat yhat_lower yhat_upper y cutoff
0 1951-12-31 -0.006353 -0.166391 0.143413 0.053849 1951-01-18
1 1952-12-31 -0.015820 -0.169072 0.145026 0.069817 1951-01-18
2 1953-12-31 -0.025520 -0.173296 0.125185 0.206579 1951-01-18
df_cv.tail(3)
ds yhat yhat_lower yhat_upper y cutoff
117 2018-12-31 0.104307 -0.092542 0.308903 0.959662 2001-01-05
118 2019-12-31 0.115870 -0.081466 0.311119 1.143743 2001-01-05
119 2020-12-31 0.129318 -0.085928 0.320792 1.275727 2001-01-05

For example, we see the the first cutoff point is in 1960. The model is trained on data up until the cutoff, then predictions (yhat) are made for the next 20 years. The cutoff points are then incremented by 10 years until 2000. I’ll measure model performance using mean squared error (MSE), but a variety of metrics could be used. We can plot MSE as a function of horizon length (how far in time the prediction is made) using plot_cross_validation_metric(); unsurprisingly, performance is worse the farther out the window:

from prophet.plot import plot_cross_validation_metric

fig, ax = plt.subplots(figsize=(10, 6))
plot_cross_validation_metric(df_cv, metric="mse", rolling_window=0.1, ax=ax, color="C0")
plot_cross_validation_metric(df_cv, metric="mse", rolling_window=0.5, ax=ax, color="C1")
plt.show()
../_images/forecast_25_0.png

The two curves differ by the amount of averaging used in computing the MSE. Each point in the blue curved is averaged over 10% of the data while the orange curve is averaged over 50% of the data. The blue curve is more variable but can give estimates over shorter horizons. Setting rolling_window=1 averages over all the data, giving just a single average estimate for the MSE predicting within a 20 year horizon. A dataframe of metrics can be extracted with performance_metrics():

from prophet.diagnostics import performance_metrics

df_performance = performance_metrics(df_cv, rolling_window=1)
df_performance
horizon mse rmse mae mape mdape smape coverage
0 7300 days 0.225348 0.474709 0.358713 3.293734 1.071312 1.544548 0.383333

The above code with rolling_window=1 is useful for hyperparameter tuning. It allows us to optimizing average performance over a fixed horizon window. This is done in the code below to find the optimum seasonality period and number of Fourier terms. I also optimize over two model parameters changepoint_prior_scale and seasonality_prior_scale which control the flexibility of the changepoints and seasonalities.

import itertools

def make_grid_combinations(grid):
    """Turn a dictionary of grid points into a dictionary of all combinations
    of those grid points."""
    all_params = []
    for vals in itertools.product(*grid.values()):
        all_params.append(dict(zip(grid.keys(), vals)))
    return all_params

param_grid = {
    'period': [50, 75, 100],
    'fourier_order': [2, 4, 6],
    'changepoint_prior_scale': [.005, .05, .5],
    'seasonality_prior_scale': [.1, 1, 10],
}
all_params = make_grid_combinations(param_grid)
mses = []

# Cross-validate each combination of grid parameters to estimate MSEs
for params in all_params:
    model = Prophet(
        daily_seasonality = False,
        weekly_seasonality = False,
        yearly_seasonality = False,
        changepoint_prior_scale = params['changepoint_prior_scale'],
        seasonality_prior_scale = params['seasonality_prior_scale']
    )
    model.add_seasonality(
        name = str(params['period']) + ' year',
        period = 365 * params['period'],
        fourier_order = params['fourier_order']
    )
    model.fit(df)

    df_cv = cross_validation(model, initial='36500 days', horizon='7300 days')
    df_performance = performance_metrics(df_cv, rolling_window=1)
    mses.append(df_performance['mse'].values[0])

tuning_results = pd.DataFrame(all_params)
tuning_results['mse'] = mses
tuning_results.to_csv('tuning_results.csv', index=False)

The result is stored in a dataframe of cross-validated MSEs and the parameters used in the model:

tuning_results = pd.read_csv("./tuning_results.csv")
tuning_results
period fourier_order changepoint_prior_scale seasonality_prior_scale mse
0 50 2 0.005 0.1 0.154416
1 50 2 0.005 1.0 0.155571
2 50 2 0.005 10.0 0.156148
3 50 2 0.050 0.1 0.152661
4 50 2 0.050 1.0 0.154947
... ... ... ... ... ...
76 100 6 0.050 1.0 0.243489
77 100 6 0.050 10.0 0.245329
78 100 6 0.500 0.1 0.108537
79 100 6 0.500 1.0 0.108298
80 100 6 0.500 10.0 0.106562

81 rows × 5 columns

The best parameters, measured by MSE, are easily obtained:

import numpy as np

best_params = tuning_results.iloc[np.argmin(tuning_results["mse"]), :]
best_params
period                     75.000000
fourier_order               2.000000
changepoint_prior_scale     0.500000
seasonality_prior_scale    10.000000
mse                         0.048304
Name: 35, dtype: float64

Let’s see what the optimized model looks like:

model = Prophet(
    daily_seasonality=False,
    weekly_seasonality=False,
    yearly_seasonality=False,
    changepoint_prior_scale=0.5,
    seasonality_prior_scale=10.0,
)
model.add_seasonality("centuryly", period=365 * 75, fourier_order=2)
model.fit(df)
future = model.make_future_dataframe(periods=30, freq="Y")
forecast = model.predict(future)
model.plot(forecast, xlabel="Year", ylabel="Temperature (C)")
plt.show()
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
/home/adam/projects/website/env/lib/python3.9/site-packages/prophet/forecaster.py:896: 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)
Initial log joint probability = -17.5035
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
      99       302.408    0.00570823       11.3782           1           1      120   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     119       303.216   0.000781285       20.5453   2.855e-05       0.001      185  LS failed, Hessian reset 
     199       304.138   7.30153e-05        7.3618      0.4801      0.4801      290   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     272       304.446   0.000393317       11.4501   2.713e-05       0.001      419  LS failed, Hessian reset 
     299       304.522   0.000217305       7.42838      0.3201      0.3201      452   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     346       304.735    0.00183216       21.7699   0.0001859       0.001      537  LS failed, Hessian reset 
     399       304.865   0.000122705       8.81822      0.3029           1      608   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     448       304.947   0.000699382       14.9056   8.463e-05       0.001      714  LS failed, Hessian reset 
     499       304.979   2.88487e-05       7.75454      0.3058      0.3058      774   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     551       304.984   0.000253777        7.0285   3.633e-05       0.001      887  LS failed, Hessian reset 
     599       304.986   9.19244e-06       7.14222           1           1      950   
    Iter      log prob        ||dx||      ||grad||       alpha      alpha0  # evals  Notes 
     602       304.986   1.93406e-05       6.94598   2.726e-06       0.001      992  LS failed, Hessian reset 
     625       304.986   3.04125e-07       6.87252      0.4057           1     1021   
Optimization terminated normally: 
  Convergence detected: relative gradient magnitude is below tolerance
../_images/forecast_34_2.png