Prophet: Automatic Forecasting Procedure

repository·main·Indexed 11 days ago

https://github.com/facebook/prophet

An automatic forecasting procedure for time series data using an additive model. Prophet is designed to handle seasonality, holidays, and trend shifts, making it ideal for business forecasting. It provides implementations for both Python and R, supporting features like warm-starting, min-max scaling for large values, and serialization via JSON.

Tokens
32.1K
Snippets
125
Records
142
Agent score
97%

What's inside Prophet

  1. What is Prophet and how does it work?

    main

    Prophet is an automatic forecasting procedure for time series data. It uses an additive model where non-linear trends are fit with yearly, weekly, and daily seasonality, plus holiday effects.

    It is particularly effective for:

    • Time series with strong seasonal effects.
    • Data with several seasons of historical data.
    • Data with missing values or shifts in trend.
    • Data containing outliers.
  2. How outliers affect Prophet forecasts

    main

    Outliers in historical data can negatively impact Prophet forecasts in two primary ways:

    1. Uncertainty Interval Inflation: Prophet may attempt to fit outliers by introducing trend changes. Because the uncertainty model expects future trend changes of similar magnitude, the resulting uncertainty intervals (the shaded area around the forecast) will become excessively wide.
    2. Seasonality Distortion: Extreme outliers occurring in specific seasonal windows (e.g., a specific month) can corrupt the seasonality estimates. This causes the error to reverberate into the future during every subsequent occurrence of that season.

    While Prophet can technically handle outliers by fitting them, it often leads to inaccurate uncertainty or seasonality modeling.

  3. Adjust Prior Scales for Holidays and Seasonality

    main

    If holidays or seasonalities are overfitting, you can dampen their effects by reducing their prior scales. This increases regularization.

    • Global Holiday Scale: Use holidays_prior_scale (Python) or holidays.prior.scale (R) in the model constructor to adjust all holidays.
    • Global Seasonality Scale: Use seasonality_prior_scale (Python) or seasonality.prior.scale (R) in the model constructor.
    • Individual Holiday Scale: Include a prior_scale column in your holidays dataframe.
    • Individual Seasonality Scale: Pass prior_scale as an argument to add_seasonality.
    # Python
    # Dampen holiday effects
    m = Prophet(holidays=holidays, holidays_prior_scale=0.05).fit(df)
    
    # Set specific scale for a custom seasonality
    m.add_seasonality(name='weekly', period=7, fourier_order=3, prior_scale=0.1)
    
    # R
    m <- prophet(df, holidays = holidays, holidays.prior.scale = 0.05)
    m <- add_seasonality(m, name='weekly', period=7, fourier.order=3, prior.scale=0.1)
  4. How automatic changepoint detection works in Prophet

    main

    Prophet detects abrupt changes in time series trajectories by identifying potential changepoints. It places a large number of potential points (default is 25) uniformly across the first 80% of the time series. To prevent overfitting, Prophet applies a sparse prior (equivalent to L1 regularization) on the magnitudes of the rate changes, meaning it only uses a subset of these potential points where actual changes occur.

    Key parameters for automatic detection:

    • n_changepoints: Sets the number of potential changepoints (default is 25).
    • changepoint_range: Determines the proportion of the history where potential changepoints are placed. The default is 0.8 (80%). Increasing this (e.g., to 0.9) allows detection closer to the end of the series, but may increase overfitting risk at the tail.

    You can visualize the detected changepoints on a plot using the add_changepoints_to_plot utility.

    # Python
    from prophet.plot import add_changepoints_to_plot
    fig = m.plot(forecast)
    a = add_changepoints_to_plot(fig.gca(), m, forecast)
    
    # R
    plot(m, forecast) + add_changepoints_to_plot(m)
  5. Use a flat trend growth rate

    main

    If your time series exhibits strong seasonality rather than trend changes, or if you are performing causal inference using exogenous regressors, you can force the trend growth rate to be flat. This prevents the model from assuming an increasing or decreasing trend, which can lead to over-prediction when using regressors.

    Set growth='flat' when initializing the model.

    # R
    m <- prophet(df, growth='flat')
    # Python
    m = Prophet(growth='flat')
  6. Data requirements for Prophet

    main

    Regardless of whether you use the Python or R API, the input data must be a dataframe with exactly two columns:

    1. ds (datestamp): Must be a format compatible with Pandas (for Python) or R, ideally YYYY-MM-DD for dates or YYYY-MM-DD HH:MM:SS for timestamps.
    2. y: A numeric column representing the measurement you wish to forecast.

    Example structure:

    dsy
    2007-12-109.590761
    2007-12-118.519590
  7. Enable uncertainty in seasonality via MCMC sampling

    main

    By default, Prophet only provides uncertainty for the trend and observation noise. To include uncertainty in seasonality estimates, you must perform full Bayesian sampling using the mcmc_samples (Python) or mcmc.samples (R) parameter.

    Setting this parameter replaces the standard MAP estimation with MCMC sampling. This process is significantly more computationally intensive and can take minutes instead of seconds depending on the dataset size. When enabled, seasonal components in component plots will display uncertainty intervals.

    # Python
    m = Prophet(mcmc_samples=300)
    forecast = m.fit(df, show_progress=False).predict(future)
  8. Handle uncertainty in future regressor values with nested Prophet models

    main

    When using extra regressors in a multi-stage prediction pipeline, their future values are often unknown and carry uncertainty. As of Prophet v1.4.0, you can use nested Prophet models to integrate regressor forecasting directly into the main model's .predict() and cross_validate() workflows.

    How it works:

    1. Enable Nested Models: When calling .add_regressor(), set the regressor_predictor parameter (or predict_spec in some contexts) to enable a nested model.
      • Setting regressor_predictor=True uses default settings.
      • Passing a dictionary (e.g., regressor_predictor={'seasonality_prior_scale': 10.0}) allows for custom configuration of the nested model.
      • Limitation: Only simple nested Prophet models are supported. You cannot use nested models that require custom seasonalities via .add_seasonality() or their own additional regressors via .add_regressor().
    2. Prediction: When you call .predict() on the main model, the regressor values are automatically filled using the yhat values generated by their respective nested Prophet models.
    3. Cross-Validation: When running cross_validate(), the main model will first predict the regressor values for the lookahead range using the nested models. This prevents data leakage and ensures cross-validation results are not overstated by using known future regressor values.
    from prophet import Prophet
    
    # Initialize main model
    m1 = Prophet(changepoint_range=0.9, seasonality_prior_scale=5.0)
    
    # Add a regressor with a nested Prophet model to handle its own uncertainty
    # Using a dictionary to pass custom configuration to the nested model
    m1.add_regressor(
        "location_4", 
        mode="additive", 
        regressor_predictor={"seasonality_prior_scale": 10.0}
    )
    
    # Fit the main model (this will also fit the nested regressor model)
    m1.fit(train_df)
    
    # Predict (the regressor values are automatically forecasted by the nested model)
    preds = m1.predict(test_df)
  9. Include holidays in aggregated data

    main

    Holiday effects in Prophet are applied to the specific date provided in the holiday dataframe. If your data is aggregated (e.g., weekly or monthly), a holiday that falls on a different day than your data point's timestamp will be ignored.

    Example: If you have weekly data where every observation is recorded on a Sunday, but a holiday falls on a Monday, the holiday effect will not be captured.

    Solution: Manually move the holiday date in your holiday dataframe to match the date used in your historical data (e.g., move the Monday holiday to the Sunday timestamp of that week). Note that for aggregated data, many holiday effects may already be captured by yearly seasonality.

  10. Adjust Fourier Order for Seasonalities

    main

    Seasonalities are modeled using partial Fourier sums. The fourier_order (Python) or fourier.order (R) determines how quickly the seasonality can change.

    • Higher order: Fits higher-frequency changes and less smooth patterns, but increases the risk of overfitting.
    • Lower order: Produces smoother seasonal patterns.

    You can specify the Fourier order for built-in seasonalities (like yearly_seasonality) when instantiating the model.

    # Python
    # Increasing yearly seasonality Fourier order to 20
    m = Prophet(yearly_seasonality=20).fit(df)
    
    # R
    m <- prophet(df, yearly.seasonality = 20)
  11. Handle data with regular gaps

    main

    If your historical data contains regular gaps (e.g., only observations from 12a to 6a, or only weekdays), Prophet's seasonality models (daily, weekly, etc.) will be unconstrained for the missing periods. This often leads to poor forecasts with large, unrealistic fluctuations during the gaps.

    Solution: Limit your future dataframe to only include the time windows present in your historical data. This ensures you only make predictions for the periods where the seasonality is well-estimated.

    # Python example: filtering future dataframe to match historical hour gaps
    df2 = df.copy()
    df2['ds'] = pd.to_datetime(df2['ds'])
    df2 = df2[df2['ds'].dt.hour < 6]
    
    m = Prophet().fit(df2)
    future = m.make_future_dataframe(periods=300, freq='H')
    
    # CRITICAL: Filter future to only include hours present in history
    future2 = future.copy()
    future2 = future2[future2['ds'].dt.hour < 6]
    
    fcst = m.predict(future2)
    fig = m.plot(fcst)
  12. Configure the documentation site structure

    main

    Documentation files are written in Markdown and must include a YAML front matter header to define metadata. The filename itself is less important than the docid and permalink values, which must be unique.

    Required YAML header fields:

    • docid: A unique identifier for the document.
    • title: The display title of the page.
    • layout: The template layout to use (e.g., docs).
    • permalink: The unique URL path for the document.
    ---
    docid: getting-started
    title: Getting started with ProjectName
    layout: docs
    permalink: /docs/getting-started.html
    ---