prophet/notebooks/additional_topics.ipynb
2020-08-19 16:29:50 -07:00

139 lines
5.5 KiB
Text

{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"%load_ext rpy2.ipython\n",
"%matplotlib inline\n",
"import pandas as pd\n",
"from fbprophet import Prophet\n",
"import logging\n",
"logging.getLogger('fbprophet').setLevel(logging.ERROR)\n",
"import warnings\n",
"warnings.filterwarnings(\"ignore\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Flat trend and custom trends\n",
"\n",
"For time series that exhibit strong seasonality patterns rather than trend changes, it may be useful to force the trend growth rate to be flat. This can be achieved simply by passing `growth=flat` when creating the model:"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [],
"source": [
"m = Prophet(growth='flat')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This is currently implemented only in the Python version of Prophet. Note that if this is used on a time series that doesn't have a constant trend, any trend will be fit with the noise term and so there will be high predictive uncertainty in the forecast.\n",
"\n",
"To use a trend besides these three built-in trend functions (piecewise linear, piecewise logistic growth, and flat), you can download the source code from github, modify the trend function as desired in a local branch, and then install that local version. This PR provides a good illustration of what must be done to implement a custom trend: https://github.com/facebook/prophet/pull/1466/files."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Partial Fitting "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Prophet also allows the option of partial fitting i.e. using a previous model's fitted parameters to initialize parameters of a new model. This could be useful when the model needs to be re-trained with new data coming in e.g. online learning. This works best when the newly added data follows the same trend as the history that has been previously fitted. An example is shown below in Python using the Peyton Manning dataset introduced in the <a href=\"https://facebook.github.io/prophet/docs/quick_start.html#python-api\">Quick Start</a>. In this case, a model `m1` is initially fit to `df1` with two years less history. A new model `m2` is then fit to `df` with full history, with parameters initialised to `m1`parameter values. These are passed to the `init` keyword as a dictionary by calling `stan_init`. Depending on the dataset, this can lead to an improvement in training time, as the parameters passed downstream to Stan's optimizing function have a more optimal initialization from the previous model's fit. In this case, we get over 20% improvement in training time compared to fitting model `m` to `df` with default parameter initialization (without partial fitting)."
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"2.41 s ± 52.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n",
"3.06 s ± 35.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n"
]
}
],
"source": [
"def stan_init(m):\n",
" \"\"\"Retrieving parameters from a trained model.\n",
" \n",
" Retrieved parameters from a trained model \n",
" of the Prophet() Class,are used to initialise \n",
" parameters for a new model. This can help \n",
" speed up training, especially if new data\n",
" follows the same trend as the historical data.\n",
" \n",
" @Param\n",
" m: A trained model of the Prophet() Class\n",
" \n",
" @Return\n",
" res: A Dictionary containing retrieved parameters of m\n",
" \n",
" \"\"\"\n",
" res = {}\n",
" for pname in ['k', 'm', 'sigma_obs']:\n",
" res[pname] = m.params[pname][0][0]\n",
" for pname in ['delta', 'beta']:\n",
" res[pname] = m.params[pname][0]\n",
" return res\n",
"\n",
"df = pd.read_csv('../examples/example_wp_log_peyton_manning.csv')\n",
"df1 = df.loc[df['ds'] < '2014-01-21', :]\n",
"m1 = Prophet()\n",
"m1.fit(df1)\n",
"\n",
"%timeit m2 = Prophet().fit(df, init=stan_init(m1))\n",
"%timeit m = Prophet().fit(df)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, there are few caveats that need to kept in mind with this approach, which could lead to a bad model fit and worse results than using the default intiialization.\n",
"\n",
"* The number of changepoints need to be consistent from one model to the next. Otherwise, an error will be generated because the changepoint prior parameter `delta` will be the wrong size.\n",
"* If the locations of the changepoints in time have changed greatly, this may do worse than the default initialization because the initial trend may be very bad."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}