Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent NaN pattern in multi-step predictions with n_lags and n_forecasts #1669

Open
rakendd opened this issue Dec 20, 2024 · 1 comment

Comments

@rakendd
Copy link

rakendd commented Dec 20, 2024

Description

I've noticed an inconsistent pattern in how NeuralProphet handles multi-step predictions. When using n_lags and n_forecasts, there appears to be a non-intuitive pattern of NaN values in the predictions.

Minimal Reproducible Example

import pandas as pd
import numpy as np
from neuralprophet import NeuralProphet

# Create simple synthetic data
dates = pd.date_range(start='2024-01-01', end='2024-01-07', freq='H')
values = np.sin(np.arange(len(dates)) * 2 * np.pi / 24) + 100  # Simple sine wave
df = pd.DataFrame({
    'ds': dates,
    'y': values
})

# Configure model with minimal lags and forecasts for clarity
model = NeuralProphet(
    daily_seasonality=True,
    weekly_seasonality=False,
    yearly_seasonality=False,
    n_lags=2,        # Using 2 lags for simplicity
    n_forecasts=2    # Predicting 2 steps ahead
)

# Fit model
model.fit(df, freq='H')

# Make predictions
forecast = model.predict(df)

Current Behavior

At the start of predictions:

                     ds           y      yhat1      yhat2        ar1        ar2      trend  season_daily
0 2024-01-01 00:00:00  100.000000        NaN        NaN        NaN        NaN        NaN          NaN
1 2024-01-01 01:00:00  100.258819        NaN        NaN        NaN        NaN        NaN          NaN
2 2024-01-01 02:00:00  100.500000  100.089165        NaN   2.082256        NaN   97.515648    0.491260
3 2024-01-01 03:00:00  100.707107  100.309059  100.692818   2.078422   2.462183   97.525993    0.704645

At row 2, we have:

  • 2 lags of history available (rows 0 and 1)
  • yhat1 is predicted
  • yhat2 is NaN despite having sufficient history

Expected Behavior

At row 2, since we have the required 2 lags of history, we should be able to predict both yhat1 and yhat2. There's no mathematical reason why we can predict one step ahead but not two steps ahead when we have all the required historical data.

Expected output at row 2:

                     ds           y      yhat1      yhat2        ar1        ar2      trend  season_daily
2 2024-01-01 02:00:00  100.500000  100.089165  100.xxxxx   2.082256   2.xxxxx   97.515648    0.491260

Questions

  1. Why does yhat2 require an additional timestamp beyond what yhat1 requires, when both predictions are based on the same historical lags?
  2. Is this a design choice or a limitation in the current implementation?
  3. If it's a design choice, could you explain the reasoning behind requiring different amounts of history for different forecast horizons?

Environment

  • NeuralProphet version: 0.9.0
  • Python version: 3.11
  • Operating System: Ubuntu
@rakendd
Copy link
Author

rakendd commented Dec 20, 2024

Further Analysis Based on Code Review

After reviewing the NeuralProphet implementation, I've found that the NaN pattern cannot be explained by recursive dependencies, as NeuralProphet actually uses direct multi-step forecasting, not recursive forecasting.

Key Code Evidence

The autoregression implementation in NeuralProphet shows that all forecasts are generated simultaneously in a single forward pass:

def auto_regression(self, lags: Union[torch.Tensor, float]) -> torch.Tensor:
    x = self.ar_net(lags)  # Takes lags as input
    x = x.view(x.shape[0], self.config_model.n_forecasts, len(self.quantiles))  # Outputs all forecasts at once
    return x

This indicates that:

  1. The model takes the lag values as input
  2. Processes them through the AR network
  3. Outputs predictions for all future steps simultaneously
  4. Does NOT use yhat1 to compute yhat2, yhat2 to compute yhat3, etc.

Implications

Given this implementation:

                     ds           y      yhat1      yhat2        ar1        ar2      trend  season_daily
2 2024-01-01 02:00:00  100.500000  100.089165        NaN   2.082256        NaN   97.515648    0.491260

At row index 2:

  • We have the required 2 lags available
  • The model generates yhat1 using these lags
  • Since it's using direct multi-step forecasting, it should also be able to generate yhat2 at the same time
  • There's no architectural reason why yhat2 should be NaN when yhat1 is available

Conclusion

The diagonal pattern of NaNs appears to be an implementation artifact rather than a necessary feature of the model's architecture. Since NeuralProphet uses direct multi-step forecasting (not recursive forecasting), all forecast horizons should theoretically be available as soon as we have sufficient lags.

This suggests that the handling of NaN values in the prediction output might need to be reviewed, as it doesn't align with the actual forecasting mechanism being used in the model.

Would it be possible to review how predictions are being assigned to the output DataFrame? It seems there might be a disconnect between how the predictions are generated (all at once) and how they're being populated in the results.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant