Add predict_columns parameter to cross validation (#2486)

This commit is contained in:
dchiang00 2023-09-19 18:56:04 -07:00 committed by GitHub
parent 265ac0550b
commit 53b9b1a6be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 24 additions and 4 deletions

View file

@ -58,7 +58,7 @@ def generate_cutoffs(df, horizon, initial, period):
return list(reversed(result)) return list(reversed(result))
def cross_validation(model, horizon, period=None, initial=None, parallel=None, cutoffs=None, disable_tqdm=False): def cross_validation(model, horizon, period=None, initial=None, parallel=None, cutoffs=None, disable_tqdm=False, extra_output_columns=None):
"""Cross-Validation for time series. """Cross-Validation for time series.
Computes forecasts from historical cutoff points, which user can input. Computes forecasts from historical cutoff points, which user can input.
@ -82,8 +82,6 @@ def cross_validation(model, horizon, period=None, initial=None, parallel=None, c
cross validation. If not provided, they are generated as described cross validation. If not provided, they are generated as described
above. above.
parallel : {None, 'processes', 'threads', 'dask', object} parallel : {None, 'processes', 'threads', 'dask', object}
disable_tqdm: if True it disables the progress bar that would otherwise show up when parallel=None
How to parallelize the forecast computation. By default no parallelism How to parallelize the forecast computation. By default no parallelism
is used. is used.
@ -110,6 +108,10 @@ def cross_validation(model, horizon, period=None, initial=None, parallel=None, c
] ]
return results return results
disable_tqdm: if True it disables the progress bar that would otherwise show up when parallel=None
extra_output_columns: A String or List of Strings e.g. 'trend' or ['trend'].
Additional columns to 'yhat' and 'ds' to be returned in output.
Returns Returns
------- -------
A pd.DataFrame with the forecast, actual value and cutoff. A pd.DataFrame with the forecast, actual value and cutoff.
@ -120,11 +122,16 @@ def cross_validation(model, horizon, period=None, initial=None, parallel=None, c
df = model.history.copy().reset_index(drop=True) df = model.history.copy().reset_index(drop=True)
horizon = pd.Timedelta(horizon) horizon = pd.Timedelta(horizon)
predict_columns = ['ds', 'yhat'] predict_columns = ['ds', 'yhat']
if model.uncertainty_samples: if model.uncertainty_samples:
predict_columns.extend(['yhat_lower', 'yhat_upper']) predict_columns.extend(['yhat_lower', 'yhat_upper'])
if extra_output_columns is not None:
if isinstance(extra_output_columns, str):
extra_output_columns = [extra_output_columns]
predict_columns.extend([c for c in extra_output_columns if c not in predict_columns])
# Identify largest seasonality period # Identify largest seasonality period
period_max = 0. period_max = 0.
for s in model.seasonalities.values(): for s in model.seasonalities.values():

View file

@ -102,6 +102,19 @@ class TestCrossValidation:
# check single forecast function called expected number of times # check single forecast function called expected number of times
assert n_calls == forecasts assert n_calls == forecasts
@pytest.mark.parametrize("extra_output_columns", ["trend", ["trend"]])
def test_check_extra_output_columns_cross_validation(self, ts_short, backend, extra_output_columns):
m = Prophet(stan_backend=backend)
m.fit(ts_short)
df_cv = diagnostics.cross_validation(
m,
horizon="1 days",
period="1 days",
initial="140 days",
extra_output_columns=extra_output_columns
)
assert "trend" in df_cv.columns
@pytest.mark.parametrize("growth", ["logistic", "flat"]) @pytest.mark.parametrize("growth", ["logistic", "flat"])
def test_cross_validation_logistic_or_flat_growth(self, growth, ts_short, backend): def test_cross_validation_logistic_or_flat_growth(self, growth, ts_short, backend):
df = ts_short.copy() df = ts_short.copy()