mirror of
https://github.com/saymrwulf/prophet.git
synced 2026-05-16 21:00:16 +00:00
Add helper function to summarise coefficients of extra regressors (#1572)
* add regressor summary fn for python * styling, docstring * update docstring * fix definition for multiplicative regressor, add tests * simpler shape test
This commit is contained in:
parent
1053a6e9ce
commit
40b170b95a
2 changed files with 119 additions and 0 deletions
41
python/fbprophet/tests/test_utilities.py
Normal file
41
python/fbprophet/tests/test_utilities.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
from unittest import TestCase
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from fbprophet import Prophet
|
||||
from fbprophet.utilities import regressor_coefficients
|
||||
|
||||
|
||||
DATA = pd.read_csv(
|
||||
os.path.join(os.path.dirname(__file__), 'data.csv'),
|
||||
parse_dates=['ds'],
|
||||
)
|
||||
|
||||
class TestUtilities(TestCase):
|
||||
def test_regressor_coefficients(self):
|
||||
m = Prophet()
|
||||
N = DATA.shape[0]
|
||||
df = DATA.copy()
|
||||
np.random.seed(123)
|
||||
df['regr1'] = np.random.normal(size=N)
|
||||
df['regr2'] = np.random.normal(size=N)
|
||||
m.add_regressor('regr1', mode='additive')
|
||||
m.add_regressor('regr2', mode='multiplicative')
|
||||
m.fit(df)
|
||||
|
||||
coefs = regressor_coefficients(m)
|
||||
self.assertTrue(coefs.shape == (2, 6))
|
||||
# No MCMC sampling, so lower and upper should be the same as mean
|
||||
self.assertTrue(np.array_equal(coefs['coef_lower'].values, coefs['coef'].values))
|
||||
self.assertTrue(np.array_equal(coefs['coef_upper'].values, coefs['coef'].values))
|
||||
78
python/fbprophet/utilities.py
Normal file
78
python/fbprophet/utilities.py
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# Copyright (c) Facebook, Inc. and its affiliates.
|
||||
|
||||
# This source code is licensed under the MIT license found in the
|
||||
# LICENSE file in the root directory of this source tree.
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
|
||||
def regressor_index(m, name):
|
||||
"""Given the name of a regressor, return its (column) index in the `beta` matrix.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
m: Prophet model object, after fitting.
|
||||
name: Name of the regressor, as passed into the `add_regressor` function.
|
||||
|
||||
Returns
|
||||
-------
|
||||
The column index of the regressor in the `beta` matrix.
|
||||
"""
|
||||
return np.extract(
|
||||
m.train_component_cols[name] == 1, m.train_component_cols.index
|
||||
)[0]
|
||||
|
||||
def regressor_coefficients(m):
|
||||
"""Summarise the coefficients of the extra regressors used in the model.
|
||||
|
||||
For additive regressors, the coefficient represents the incremental impact
|
||||
on `y` of a unit increase in the regressor. For multiplicative regressors,
|
||||
the incremental impact is equal to `trend(t)` multiplied by the coefficient.
|
||||
|
||||
Coefficients are measured on the original scale of the training data.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
m: Prophet model object, after fitting.
|
||||
|
||||
Returns
|
||||
-------
|
||||
pd.DataFrame containing:
|
||||
- `regressor`: Name of the regressor
|
||||
- `regressor_mode`: Whether the regressor has an additive or multiplicative
|
||||
effect on `y`.
|
||||
- `center`: The mean of the regressor if it was standardized. Otherwise 0.
|
||||
- `coef_lower`: Lower bound for the coefficient, estimated from the MCMC samples.
|
||||
Only different to `coef` if `mcmc_samples > 0`.
|
||||
- `coef`: Expected value of the coefficient.
|
||||
- `coef_upper`: Upper bound for the coefficient, estimated from MCMC samples.
|
||||
Only to different to `coef` if `mcmc_samples > 0`.
|
||||
"""
|
||||
assert len(m.extra_regressors) > 0, 'No extra regressors found.'
|
||||
y_max = m.history['y'].max()
|
||||
coefs = []
|
||||
for regressor, params in m.extra_regressors.items():
|
||||
beta = m.params['beta'][:, regressor_index(m, regressor)]
|
||||
if params['mode'] == 'additive':
|
||||
coef = beta * y_max / params['std']
|
||||
else:
|
||||
coef = beta / params['std']
|
||||
percentiles = [
|
||||
(1 - m.interval_width) / 2,
|
||||
1 - (1 - m.interval_width) / 2,
|
||||
]
|
||||
coef_bounds = np.quantile(coef, q=percentiles)
|
||||
record = {
|
||||
'regressor': regressor,
|
||||
'regressor_mode': params['mode'],
|
||||
'center': params['mu'],
|
||||
'coef_lower': coef_bounds[0],
|
||||
'coef': np.mean(coef),
|
||||
'coef_upper': coef_bounds[1],
|
||||
}
|
||||
coefs.append(record)
|
||||
|
||||
return pd.DataFrame(coefs)
|
||||
Loading…
Reference in a new issue