mirror of
https://github.com/saymrwulf/prophet.git
synced 2026-09-16 22:20:23 +00:00
Documentation for cross validation
This commit is contained in:
parent
6c446cee85
commit
2f9b20b2d3
6 changed files with 332 additions and 81 deletions
|
|
@ -27,19 +27,21 @@ generate_cutoffs <- function(df, horizon, k, period) {
|
||||||
}
|
}
|
||||||
tzone <- attr(cutoff, "tzone") # Timezone is wiped by putting in array
|
tzone <- attr(cutoff, "tzone") # Timezone is wiped by putting in array
|
||||||
result <- c(cutoff)
|
result <- c(cutoff)
|
||||||
for (i in 2:k) {
|
if (k > 1) {
|
||||||
cutoff <- cutoff - period
|
for (i in 2:k) {
|
||||||
# If data does not exist in data range (cutoff, cutoff + horizon]
|
cutoff <- cutoff - period
|
||||||
if (!any((df$ds > cutoff) & (df$ds <= cutoff + horizon))) {
|
# If data does not exist in data range (cutoff, cutoff + horizon]
|
||||||
# Next cutoff point is 'closest date before cutoff in data - horizon'
|
if (!any((df$ds > cutoff) & (df$ds <= cutoff + horizon))) {
|
||||||
closest.date <- max(df$ds[df$ds <= cutoff])
|
# Next cutoff point is 'closest date before cutoff in data - horizon'
|
||||||
cutoff <- closest.date - horizon
|
closest.date <- max(df$ds[df$ds <= cutoff])
|
||||||
|
cutoff <- closest.date - horizon
|
||||||
|
}
|
||||||
|
if (cutoff < min(df$ds)) {
|
||||||
|
warning('Not enough data for requested number of cutoffs! Using ', i)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result <- c(result, cutoff)
|
||||||
}
|
}
|
||||||
if (cutoff < min(df$ds)) {
|
|
||||||
warning('Not enough data for requested number of cutoffs! Using ', i)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
result <- c(result, cutoff)
|
|
||||||
}
|
}
|
||||||
# Reset timezones
|
# Reset timezones
|
||||||
attr(result, "tzone") <- tzone
|
attr(result, "tzone") <- tzone
|
||||||
|
|
@ -47,8 +49,9 @@ generate_cutoffs <- function(df, horizon, k, period) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Simulated historical forecasts.
|
#' Simulated historical forecasts.
|
||||||
#' Make forecasts from k historical cutoff dates, and compare forecast values
|
#'
|
||||||
#' to actual values.
|
#' Make forecasts from k historical cutoff points, working backwards from
|
||||||
|
#' (end - horizon) with a spacing of period between each cutoff.
|
||||||
#'
|
#'
|
||||||
#' @param model Fitted Prophet model.
|
#' @param model Fitted Prophet model.
|
||||||
#' @param horizon Integer size of the horizon
|
#' @param horizon Integer size of the horizon
|
||||||
|
|
@ -99,25 +102,31 @@ simulated_historical_forecasts <- function(model, horizon, units, k,
|
||||||
}
|
}
|
||||||
|
|
||||||
#' Cross-validation for time series.
|
#' Cross-validation for time series.
|
||||||
#' Computes forecast error with cutoffs at the specified period. When the
|
#'
|
||||||
#' period is the time interval of the data, is the procedure described in
|
#' Computes forecasts from historical cutoff points. Beginning from initial,
|
||||||
#' https://robjhyndman.com/hyndsight/tscv/. Beginning from end-horizon, makes
|
#' makes cutoffs with a spacing of period up to (end - horizon).
|
||||||
#' a cutoff every "period" amount of time, going back to "initial".
|
#'
|
||||||
|
#' When period is equal to the time interval of the data, this is the
|
||||||
|
#' technique described in https://robjhyndman.com/hyndsight/tscv/ .
|
||||||
#'
|
#'
|
||||||
#' @param model Fitted Prophet model.
|
#' @param model Fitted Prophet model.
|
||||||
#' @param horizon Integer size of the horizon
|
#' @param horizon Integer size of the horizon
|
||||||
#' @param units String unit of the horizon, e.g., "days", "secs".
|
#' @param units String unit of the horizon, e.g., "days", "secs".
|
||||||
#' @param period Integer amount of time between cutoff dates. Same units as
|
#' @param period Integer amount of time between cutoff dates. Same units as
|
||||||
#' horizon.
|
#' horizon. If not provided, 0.5 * horizon is used.
|
||||||
#' @param initial Integer size of the first training period. If not provided,
|
#' @param initial Integer size of the first training period. If not provided,
|
||||||
#' 3 * horizon is used. Same units as horizon.
|
#' 3 * horizon is used. Same units as horizon.
|
||||||
#'
|
#'
|
||||||
#' @return A dataframe with the forecast, actual value, and cutoff date.
|
#' @return A dataframe with the forecast, actual value, and cutoff date.
|
||||||
#'
|
#'
|
||||||
#' @export
|
#' @export
|
||||||
cross_validation <- function(model, horizon, units, period, initial = NULL) {
|
cross_validation <- function(
|
||||||
|
model, horizon, units, period = NULL, initial = NULL) {
|
||||||
te <- max(model$history$ds)
|
te <- max(model$history$ds)
|
||||||
ts <- min(model$history$ds)
|
ts <- min(model$history$ds)
|
||||||
|
if (is.null(period)) {
|
||||||
|
period <- 0.5 * horizon
|
||||||
|
}
|
||||||
if (is.null(initial)) {
|
if (is.null(initial)) {
|
||||||
initial <- 3 * horizon
|
initial <- 3 * horizon
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +138,7 @@ cross_validation <- function(model, horizon, units, period, initial = NULL) {
|
||||||
as.double(period.dt, units = 'secs')
|
as.double(period.dt, units = 'secs')
|
||||||
)
|
)
|
||||||
if (k < 1) {
|
if (k < 1) {
|
||||||
stop('Not enough data for specified horizon and initial.')
|
stop('Not enough data for specified horizon, period, and initial.')
|
||||||
}
|
}
|
||||||
return(simulated_historical_forecasts(model, horizon, units, k, period))
|
return(simulated_historical_forecasts(model, horizon, units, k, period))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,9 @@
|
||||||
% Please edit documentation in R/diagnostics.R
|
% Please edit documentation in R/diagnostics.R
|
||||||
\name{cross_validation}
|
\name{cross_validation}
|
||||||
\alias{cross_validation}
|
\alias{cross_validation}
|
||||||
\title{Cross-validation for time series.
|
\title{Cross-validation for time series.}
|
||||||
Computes forecast error with cutoffs at the specified period. When the
|
|
||||||
period is the time interval of the data, is the procedure described in
|
|
||||||
https://robjhyndman.com/hyndsight/tscv/. Beginning from end-horizon, makes
|
|
||||||
a cutoff every "period" amount of time, going back to "initial".}
|
|
||||||
\usage{
|
\usage{
|
||||||
cross_validation(model, horizon, units, period, initial = NULL)
|
cross_validation(model, horizon, units, period = NULL, initial = NULL)
|
||||||
}
|
}
|
||||||
\arguments{
|
\arguments{
|
||||||
\item{model}{Fitted Prophet model.}
|
\item{model}{Fitted Prophet model.}
|
||||||
|
|
@ -18,7 +14,7 @@ cross_validation(model, horizon, units, period, initial = NULL)
|
||||||
\item{units}{String unit of the horizon, e.g., "days", "secs".}
|
\item{units}{String unit of the horizon, e.g., "days", "secs".}
|
||||||
|
|
||||||
\item{period}{Integer amount of time between cutoff dates. Same units as
|
\item{period}{Integer amount of time between cutoff dates. Same units as
|
||||||
horizon.}
|
horizon. If not provided, 0.5 * horizon is used.}
|
||||||
|
|
||||||
\item{initial}{Integer size of the first training period. If not provided,
|
\item{initial}{Integer size of the first training period. If not provided,
|
||||||
3 * horizon is used. Same units as horizon.}
|
3 * horizon is used. Same units as horizon.}
|
||||||
|
|
@ -27,9 +23,10 @@ horizon.}
|
||||||
A dataframe with the forecast, actual value, and cutoff date.
|
A dataframe with the forecast, actual value, and cutoff date.
|
||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Cross-validation for time series.
|
Computes forecasts from historical cutoff points. Beginning from initial,
|
||||||
Computes forecast error with cutoffs at the specified period. When the
|
makes cutoffs with a spacing of period up to (end - horizon).
|
||||||
period is the time interval of the data, is the procedure described in
|
}
|
||||||
https://robjhyndman.com/hyndsight/tscv/. Beginning from end-horizon, makes
|
\details{
|
||||||
a cutoff every "period" amount of time, going back to "initial".
|
When period is equal to the time interval of the data, this is the
|
||||||
|
technique described in https://robjhyndman.com/hyndsight/tscv/ .
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,8 @@
|
||||||
% Please edit documentation in R/prophet.R
|
% Please edit documentation in R/prophet.R
|
||||||
\name{parse_seasonality_args}
|
\name{parse_seasonality_args}
|
||||||
\alias{parse_seasonality_args}
|
\alias{parse_seasonality_args}
|
||||||
\alias{parse_seasonality_args}
|
|
||||||
\title{Get number of Fourier components for built-in seasonalities.}
|
\title{Get number of Fourier components for built-in seasonalities.}
|
||||||
\usage{
|
\usage{
|
||||||
parse_seasonality_args(m, name, arg, auto.disable, default.order)
|
|
||||||
|
|
||||||
parse_seasonality_args(m, name, arg, auto.disable, default.order)
|
parse_seasonality_args(m, name, arg, auto.disable, default.order)
|
||||||
}
|
}
|
||||||
\arguments{
|
\arguments{
|
||||||
|
|
@ -19,27 +16,12 @@ provided.}
|
||||||
|
|
||||||
\item{auto.disable}{Bool if seasonality should be disabled when 'auto'.}
|
\item{auto.disable}{Bool if seasonality should be disabled when 'auto'.}
|
||||||
|
|
||||||
\item{default.order}{Int default Fourier order.}
|
|
||||||
|
|
||||||
\item{m}{Prophet object.}
|
|
||||||
|
|
||||||
\item{name}{String name of the seasonality component.}
|
|
||||||
|
|
||||||
\item{arg}{'auto', TRUE, FALSE, or number of Fourier components as
|
|
||||||
provided.}
|
|
||||||
|
|
||||||
\item{auto.disable}{Bool if seasonality should be disabled when 'auto'.}
|
|
||||||
|
|
||||||
\item{default.order}{Int default Fourier order.}
|
\item{default.order}{Int default Fourier order.}
|
||||||
}
|
}
|
||||||
\value{
|
\value{
|
||||||
Number of Fourier components, or 0 for disabled.
|
|
||||||
|
|
||||||
Number of Fourier components, or 0 for disabled.
|
Number of Fourier components, or 0 for disabled.
|
||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Get number of Fourier components for built-in seasonalities.
|
|
||||||
|
|
||||||
Get number of Fourier components for built-in seasonalities.
|
Get number of Fourier components for built-in seasonalities.
|
||||||
}
|
}
|
||||||
\keyword{internal}
|
\keyword{internal}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,7 @@
|
||||||
% Please edit documentation in R/diagnostics.R
|
% Please edit documentation in R/diagnostics.R
|
||||||
\name{simulated_historical_forecasts}
|
\name{simulated_historical_forecasts}
|
||||||
\alias{simulated_historical_forecasts}
|
\alias{simulated_historical_forecasts}
|
||||||
\title{Simulated historical forecasts.
|
\title{Simulated historical forecasts.}
|
||||||
Make forecasts from k historical cutoff dates, and compare forecast values
|
|
||||||
to actual values.}
|
|
||||||
\usage{
|
\usage{
|
||||||
simulated_historical_forecasts(model, horizon, units, k, period = NULL)
|
simulated_historical_forecasts(model, horizon, units, k, period = NULL)
|
||||||
}
|
}
|
||||||
|
|
@ -24,7 +22,6 @@ horizon. If not provided, will use 0.5 * horizon.}
|
||||||
A dataframe with the forecast, actual value, and cutoff date.
|
A dataframe with the forecast, actual value, and cutoff date.
|
||||||
}
|
}
|
||||||
\description{
|
\description{
|
||||||
Simulated historical forecasts.
|
Make forecasts from k historical cutoff points, working backwards from
|
||||||
Make forecasts from k historical cutoff dates, and compare forecast values
|
(end - horizon) with a spacing of period between each cutoff.
|
||||||
to actual values.
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
260
notebooks/diagnostics.ipynb
Normal file
260
notebooks/diagnostics.ipynb
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -46,11 +46,13 @@ def _cutoffs(df, horizon, k, period):
|
||||||
cutoff -= period
|
cutoff -= period
|
||||||
# If data does not exist in data range (cutoff, cutoff + horizon]
|
# If data does not exist in data range (cutoff, cutoff + horizon]
|
||||||
if not (((df['ds'] > cutoff) & (df['ds'] <= cutoff + horizon)).any()):
|
if not (((df['ds'] > cutoff) & (df['ds'] <= cutoff + horizon)).any()):
|
||||||
# Next cutoff point is 'closest date before cutoff in data - horizon'
|
# Next cutoff point is 'last date before cutoff in data - horizon'
|
||||||
closest_date = df[df['ds'] <= cutoff].max()['ds']
|
closest_date = df[df['ds'] <= cutoff].max()['ds']
|
||||||
cutoff = closest_date - horizon
|
cutoff = closest_date - horizon
|
||||||
if cutoff < df['ds'].min():
|
if cutoff < df['ds'].min():
|
||||||
logger.warning('Not enough data for requested number of cutoffs! Using {}.'.format(i))
|
logger.warning(
|
||||||
|
'Not enough data for requested number of cutoffs! '
|
||||||
|
'Using {}.'.format(i))
|
||||||
break
|
break
|
||||||
result.append(cutoff)
|
result.append(cutoff)
|
||||||
|
|
||||||
|
|
@ -60,20 +62,20 @@ def _cutoffs(df, horizon, k, period):
|
||||||
|
|
||||||
def simulated_historical_forecasts(model, horizon, k, period=None):
|
def simulated_historical_forecasts(model, horizon, k, period=None):
|
||||||
"""Simulated Historical Forecasts.
|
"""Simulated Historical Forecasts.
|
||||||
If you would like to know it in detail, read the original paper
|
|
||||||
https://facebookincubator.github.io/prophet/static/prophet_paper_20170113.pdf
|
Make forecasts from k historical cutoff points, working backwards from
|
||||||
|
(end - horizon) with a spacing of period between each cutoff.
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
model: Prophet class object.
|
model: Prophet class object.
|
||||||
Fitted Prophet model
|
Fitted Prophet model
|
||||||
horizon: string which has pd.Timedelta compatible style.
|
horizon: string with pd.Timedelta compatible style, e.g., '5 days',
|
||||||
Forecast horizon ('5 days', '3 hours', '10 seconds' etc)
|
'3 hours', '10 seconds'.
|
||||||
k: Int number.
|
k: Int number of forecasts point.
|
||||||
The number of forecasts point.
|
period: Optional string with pd.Timedelta compatible style. Simulated
|
||||||
period: string which has pd.Timedelta compatible style or None, default None.
|
forecast will be done at every this period. If not provided,
|
||||||
Simulated Forecast will be done at every this period.
|
0.5 * horizon is used.
|
||||||
0.5 * horizon is used when it is None.
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
@ -108,21 +110,24 @@ def simulated_historical_forecasts(model, horizon, k, period=None):
|
||||||
return reduce(lambda x, y: x.append(y), predicts).reset_index(drop=True)
|
return reduce(lambda x, y: x.append(y), predicts).reset_index(drop=True)
|
||||||
|
|
||||||
|
|
||||||
def cross_validation(model, horizon, period, initial=None):
|
def cross_validation(model, horizon, period=None, initial=None):
|
||||||
"""Cross-Validation for time-series.
|
"""Cross-Validation for time series.
|
||||||
This function is the same with Time series cross-validation described in https://robjhyndman.com/hyndsight/tscv/
|
|
||||||
when the value of period is equal to the time interval of data.
|
Computes forecasts from historical cutoff points. Beginning from initial,
|
||||||
|
makes cutoffs with a spacing of period up to (end - horizon).
|
||||||
|
|
||||||
|
When period is equal to the time interval of the data, this is the
|
||||||
|
technique described in https://robjhyndman.com/hyndsight/tscv/ .
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
model: Prophet class object. Fitted Prophet model
|
model: Prophet class object. Fitted Prophet model
|
||||||
horizon: string which has pd.Timedelta compatible style.
|
horizon: string with pd.Timedelta compatible style, e.g., '5 days',
|
||||||
Forecast horizon ('5 days', '3 hours', '10 seconds' etc)
|
'3 hours', '10 seconds'.
|
||||||
period: string which has pd.Timedelta compatible style.
|
period: string with pd.Timedelta compatible style. Simulated forecast will
|
||||||
Simulated Forecast will be done at every this period.
|
be done at every this period. If not provided, 0.5 * horizon is used.
|
||||||
initial: string which has pd.Timedelta compatible style or None, default None.
|
initial: string with pd.Timedelta compatible style. The first training
|
||||||
First training period.
|
period will begin here. If not provided, 3 * horizon is used.
|
||||||
3 * horizon is used when it is None.
|
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
-------
|
-------
|
||||||
|
|
@ -131,9 +136,10 @@ def cross_validation(model, horizon, period, initial=None):
|
||||||
te = model.history['ds'].max()
|
te = model.history['ds'].max()
|
||||||
ts = model.history['ds'].min()
|
ts = model.history['ds'].min()
|
||||||
horizon = pd.Timedelta(horizon)
|
horizon = pd.Timedelta(horizon)
|
||||||
period = pd.Timedelta(period)
|
period = 0.5 * horizon if period is None else pd.Timedelta(period)
|
||||||
initial = 3 * horizon if initial is None else pd.Timedelta(initial)
|
initial = 3 * horizon if initial is None else pd.Timedelta(initial)
|
||||||
k = int(np.ceil(((te - horizon) - (ts + initial)) / period))
|
k = int(np.ceil(((te - horizon) - (ts + initial)) / period))
|
||||||
if k < 1:
|
if k < 1:
|
||||||
raise ValueError('Not enough data for specified horizon and initial.')
|
raise ValueError(
|
||||||
|
'Not enough data for specified horizon, period, and initial.')
|
||||||
return simulated_historical_forecasts(model, horizon, k, period)
|
return simulated_historical_forecasts(model, horizon, k, period)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue