← Back to Model Library

Prophet-LSTM Hybrid Model

Combining Decomposition with Deep Learning for Residuals

Overview

The Prophet-LSTM hybrid model combines the strengths of Facebook's Prophet forecasting procedure with the powerful non-linear learning capabilities of Long Short-Term Memory (LSTM) neural networks. This hybrid approach leverages Prophet's robust decomposition of time series into trend, seasonality, and holiday effects, and then uses an LSTM model to capture any remaining complex, non-linear patterns in the residuals (the unexplained part) from the Prophet forecast. This synergy aims to provide more accurate and robust forecasts, especially for time series data that exhibits both clear, interpretable patterns and intricate, non-linear dynamics.

Architecture & Components

The Prophet-LSTM hybrid model typically follows a two-stage sequential process:

  1. Stage 1: Prophet Modeling (Trend, Seasonality, Holidays)

    A Prophet model is first applied to the raw time series data. Prophet excels at modeling piecewise linear or logistic trends, multiple seasonalities (yearly, weekly, daily) using Fourier series, and the impact of holidays. After fitting, Prophet generates in-sample predictions, and the **residuals** (the differences between the actual values and Prophet's fitted values) are calculated. These residuals are assumed to contain the non-linear patterns that Prophet's additive model could not fully capture.

    $ R_t = Y_t - \hat{Y}_t^{\text{Prophet}} $

    Where $R_t$ are the residuals, $Y_t$ is the actual value, and $\hat{Y}_t^{\text{Prophet}}$ is Prophet's fitted value.
  2. Stage 2: LSTM Modeling (Non-linear Residuals)

    An LSTM neural network is then trained on these residuals. The LSTM's ability to learn complex non-linear relationships and long-term dependencies makes it ideal for modeling the intricate patterns that remain after Prophet has accounted for the linear and seasonal components. The LSTM takes past residuals as input and learns a function to forecast the future deviation of the Prophet predictions.

    $ \hat{R}_t^{\text{LSTM}} = \text{LSTM}(R_{t-1}, R_{t-2}, \dots, R_{t-w}) $

    Where $\hat{R}_t^{\text{LSTM}}$ is the LSTM's forecast of the residual, and $w$ is the look-back window for the LSTM.
  3. Final Forecast Combination:

    The final forecast is obtained by summing the forecasts from both components: the forecast from Prophet and the non-linear residual forecast from LSTM.

    $ \hat{Y}_t^{\text{Hybrid}} = \hat{Y}_t^{\text{Prophet}} + \hat{R}_t^{\text{LSTM}} $

Prophet-LSTM Hybrid Architecture Diagram

Conceptual diagram of the Prophet-LSTM hybrid model, showing sequential processing.

When to Use Prophet-LSTM Hybrid

The Prophet-LSTM hybrid model is particularly effective for:

  • Time series with strong seasonality and holidays, combined with complex non-linear residuals: This is common in business data where predictable calendar effects interact with subtle, hard-to-model non-linearities.
  • Achieving high forecasting accuracy: By combining complementary strengths, it often outperforms standalone Prophet or LSTM models.
  • When interpretability of the trend and seasonal components is desired: Prophet provides a clear, interpretable baseline.
  • Handling missing data and outliers: Prophet's robustness to these issues is maintained.
  • As a robust solution for challenging time series data.

Pros and Cons

Pros

  • Enhanced Accuracy: Leverages Prophet's robust handling of seasonality and holidays with LSTM's ability to capture complex non-linearities in residuals.
  • Improved Robustness: Benefits from Prophet's resilience to missing data and outliers.
  • Interpretability: Prophet's decomposition provides clear insights into the linear and seasonal components.
  • Addresses Limitations: Overcomes Prophet's limitation with complex non-linearities and LSTM's need for extensive feature engineering for seasonality.
  • Versatile: Applicable to various time series data, especially in business contexts.

Cons

  • Increased Complexity: More challenging to implement and manage due to the need to train and integrate two separate models.
  • Higher Computational Cost: Involves training two models sequentially, which can be time-consuming.
  • Error Propagation: Errors from the Prophet model can propagate to the LSTM model, potentially affecting overall performance.
  • Data Requirements: LSTMs generally require a substantial amount of data, which might be a limitation for very short series.
  • Hyperparameter Tuning: Requires tuning parameters for both Prophet and LSTM components.

Example Implementation

Implementing a Prophet-LSTM hybrid model involves several steps: fitting Prophet, extracting residuals, preparing residuals for LSTM, training LSTM, and combining forecasts. Here's a conceptual Python example demonstrating this process.

Python Example (Conceptual)

                        
import pandas as pd
import numpy as np
from prophet import Prophet
from sklearn.preprocessing import MinMaxScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from sklearn.metrics import mean_absolute_error, mean_squared_error
import matplotlib.pyplot as plt

# 1. Generate sample data with trend, seasonality, and some non-linearity
np.random.seed(42)
n_samples = 365 * 2 # 2 years of daily data
time_idx = pd.date_range(start='2020-01-01', periods=n_samples, freq='D')

# Linear trend + strong yearly seasonality
linear_seasonal_component = 100 + 0.5 * np.arange(n_samples) + 30 * np.sin(np.arange(n_samples) * 2 * np.pi / 365)
# Add some non-linear, autoregressive-like noise (residuals for LSTM)
non_linear_residuals = np.zeros(n_samples)
for i in range(1, n_samples):
    non_linear_residuals[i] = 0.4 * non_linear_residuals[i-1] + np.random.normal(0, 2) * (1 + np.cos(i/100))

original_series = linear_seasonal_component + non_linear_residuals
df_prophet = pd.DataFrame({'ds': time_idx, 'y': original_series})

# 2. Split data into train and test sets (chronological)
train_size = int(n_samples * 0.8)
train_df_prophet, test_df_prophet = df_prophet.iloc[0:train_size], df_prophet.iloc[train_size:n_samples]
train_series_actual = df_prophet['y'].iloc[0:train_size]
test_series_actual = df_prophet['y'].iloc[train_size:n_samples]

# --- Stage 1: Prophet Modeling ---
# 3. Fit Prophet model to capture linear/seasonal patterns
m = Prophet(yearly_seasonality=True, weekly_seasonality=True, daily_seasonality=False)
m.fit(train_df_prophet)

# Create future dataframe for in-sample predictions to get residuals
future_in_sample = m.make_future_dataframe(periods=0, include_history=True)
prophet_train_pred_df = m.predict(future_in_sample)
prophet_train_pred = prophet_train_pred_df['yhat'].iloc[0:train_size]

# 4. Get Prophet in-sample residuals
prophet_residuals = train_series_actual - prophet_train_pred

print("Prophet Model Fitted.")
print(f"\nProphet Residuals (first 5): {prophet_residuals.head().values}")

# --- Stage 2: LSTM Modeling on Residuals ---
# 5. Prepare residuals for LSTM (supervised learning format)
look_back = 10 # Number of past residuals to use as input for LSTM
scaler = MinMaxScaler(feature_range=(0, 1))
scaled_residuals = scaler.fit_transform(prophet_residuals.values.reshape(-1, 1))

def create_lstm_dataset(dataset, look_back=1):
    X, Y =,
    for i in range(len(dataset) - look_back):
        X.append(dataset[i:(i + look_back), 0])
        Y.append(dataset[i + look_back, 0])
    return np.array(X), np.array(Y)

X_residuals, y_residuals = create_lstm_dataset(scaled_residuals, look_back)

# Reshape input to be [samples, time steps, features] for LSTM
X_residuals = np.reshape(X_residuals, (X_residuals.shape, X_residuals.shape[1], 1))

# 6. Build and train LSTM model on residuals
lstm_model = Sequential()
lstm_model.add(LSTM(50, activation='relu', input_shape=(look_back, 1)))
lstm_model.add(Dense(1))
lstm_model.compile(optimizer='adam', loss='mean_squared_error')

print("\nStarting LSTM training on Prophet residuals...")
lstm_model.fit(X_residuals, y_residuals, epochs=50, batch_size=1, verbose=0) # Reduced epochs for demo
print("LSTM training complete.")

# --- Forecasting and Combination ---
# 7. Make multi-step forecasts
forecast_steps = len(test_series_actual)

# Prophet forecast for the future
future_prophet = m.make_future_dataframe(periods=forecast_steps, include_history=False)
prophet_forecast_future_df = m.predict(future_prophet)
prophet_forecast_future = prophet_forecast_future_df['yhat'].values

# LSTM forecast for future residuals (recursive prediction)
# Start with the last 'look_back' residuals from training
last_residuals_sequence = scaled_residuals[-look_back:]
lstm_future_residuals_scaled =
current_lstm_input = last_residuals_sequence.reshape(1, look_back, 1)

for _ in range(forecast_steps):
    next_residual_pred_scaled = lstm_model.predict(current_lstm_input, verbose=0)
    lstm_future_residuals_scaled.append(next_residual_pred_scaled)
    # Update input sequence: remove oldest, add new prediction
    current_lstm_input = np.append(current_lstm_input[:, 1:, :], [[[next_residual_pred_scaled]]], axis=1)

lstm_future_residuals = scaler.inverse_transform(np.array(lstm_future_residuals_scaled).reshape(-1, 1)).flatten()

# 8. Combine forecasts
hybrid_forecast = prophet_forecast_future + lstm_future_residuals

# 9. Evaluate Hybrid Model
mae = mean_absolute_error(test_series_actual, hybrid_forecast)
rmse = np.sqrt(mean_squared_error(test_series_actual, hybrid_forecast))
print(f"\nHybrid Model MAE: {mae:.3f}")
print(f"Hybrid Model RMSE: {rmse:.3f}")

# 10. Plotting Results
plt.figure(figsize=(14, 7))
plt.plot(train_df_prophet['ds'], train_series_actual, label='Training Data', color='blue')
plt.plot(test_df_prophet['ds'], test_series_actual, label='Actual Test Data', color='orange')
plt.plot(test_df_prophet['ds'], hybrid_forecast, label='Prophet-LSTM Hybrid Forecast', color='green', linestyle='--')
plt.title('Prophet-LSTM Hybrid Time Series Forecasting')
plt.xlabel('Date')
plt.ylabel('Value')
plt.legend()
plt.grid(True)
plt.show()
                        

Dependencies & Resources

Dependencies: pandas, numpy, prophet, tensorflow/keras, scikit-learn, matplotlib (for plotting).