The NeuralForecast class is the primary user interface for neural forecasting operations, providing 100% compatibility with the NeuralForecast Python library while leveraging Rust's performance and safety guarantees.
NeuralForecast manages a collection of forecasting models and provides high-level operations for training, prediction, and evaluation. It handles data preprocessing, model coordination, and result aggregation automatically.
- Multi-Model Support: Manage multiple forecasting models simultaneously
- Automatic Preprocessing: Built-in data scaling and preprocessing
- Parallel Processing: Multi-threaded training and prediction
- Cross-Validation: Time series-aware cross-validation
- Prediction Intervals: Probabilistic forecasting with confidence bounds
- Model Persistence: Save and load trained models
pub struct NeuralForecast<T: Float + Send + Sync> {
models: Vec<Box<dyn BaseModel<T>>>,
frequency: Frequency,
local_scaler_type: Option<ScalerType>,
num_threads: Option<usize>,
prediction_intervals: Option<PredictionIntervals>,
device: Device,
is_fitted: bool,
training_schema: Option<TimeSeriesSchema>,
model_metadata: HashMap<String, ModelInfo>,
}use neuro_divergent::{NeuralForecast, models::LSTM, Frequency, ScalerType, Device};
let nf = NeuralForecast::builder()
.with_model(Box::new(lstm_model))
.with_frequency(Frequency::Daily)
.with_local_scaler(ScalerType::StandardScaler)
.with_num_threads(4)
.with_device(Device::CPU)
.build()?;let models = vec![Box::new(lstm_model), Box::new(nbeats_model)];
let nf = NeuralForecast::new(models, Frequency::Daily)?;Trains all models on the provided time series data.
Parameters:
data- Time series data for training
Returns:
Ok(())- If training succeeds for all modelsErr(NeuroDivergentError)- If any model training fails
Example:
// Load training data
let data = TimeSeriesDataFrame::from_csv("train_data.csv")?;
// Fit all models
nf.fit(data)?;
println!("All models trained successfully");Notes:
- Models are trained in parallel if
num_threads > 1 - Data is automatically preprocessed using the configured scaler
- Training schema is stored for validation of future data
- Model metadata is updated with training statistics
fit_with_validation(&mut self, data: TimeSeriesDataFrame<T>, validation_config: ValidationConfig) -> NeuroDivergentResult<()>
Trains models with custom validation configuration.
Parameters:
data- Training datavalidation_config- Validation settings (split ratio, shuffle, etc.)
Example:
let validation_config = ValidationConfig::new()
.with_validation_split(0.2)
.with_shuffle(true)
.with_random_seed(42);
nf.fit_with_validation(data, validation_config)?;Generates forecasts using all fitted models.
Returns:
Ok(ForecastDataFrame<T>)- Forecast results from all modelsErr(NeuroDivergentError)- If models are not fitted or prediction fails
Example:
// Generate forecasts
let forecasts = nf.predict()?;
// Access forecasts by model
for model_name in nf.model_names() {
let model_forecasts = forecasts.get_model_forecasts(&model_name)?;
println!("{}: {:?}", model_name, model_forecasts);
}Generates forecasts for new input data.
Parameters:
data- New time series data to forecast
Example:
// Load new data
let new_data = TimeSeriesDataFrame::from_csv("new_data.csv")?;
// Generate forecasts for new data
let forecasts = nf.predict_on(new_data)?;Generates forecasts with custom prediction configuration.
Parameters:
config- Prediction settings (intervals, sampling, etc.)
Example:
let prediction_config = PredictionConfig::new()
.with_intervals()
.with_num_samples(1000)
.with_temperature(0.8);
let forecasts = nf.predict_with_config(prediction_config)?;cross_validation(&mut self, data: TimeSeriesDataFrame<T>, config: CrossValidationConfig) -> NeuroDivergentResult<CrossValidationDataFrame<T>>
Performs time series cross-validation for model evaluation.
Parameters:
data- Full dataset for cross-validationconfig- Cross-validation configuration
Returns:
Ok(CrossValidationDataFrame<T>)- Cross-validation resultsErr(NeuroDivergentError)- If validation fails
Example:
let cv_config = CrossValidationConfig::new(3, 12) // 3 windows, 12-step horizon
.with_step_size(1)
.with_refit(false);
let cv_results = nf.cross_validation(data, cv_config)?;
// Analyze results
println!("CV cutoffs: {:?}", cv_results.cutoffs());
let metrics = cv_results.metrics();
for (model_name, model_metrics) in metrics {
println!("{}: MAE = {:.4}", model_name, model_metrics.get("MAE").unwrap());
}fit_predict(&mut self, train_data: TimeSeriesDataFrame<T>) -> NeuroDivergentResult<ForecastDataFrame<T>>
Convenience method that fits models and generates predictions in one call.
Example:
let forecasts = nf.fit_predict(train_data)?;Returns the names of all models in the ensemble.
Returns the number of models in the ensemble.
Checks if all models have been trained.
Returns the time series frequency.
Example:
println!("Models: {:?}", nf.model_names());
println!("Model count: {}", nf.num_models());
println!("Fitted: {}", nf.is_fitted());
println!("Frequency: {}", nf.frequency());Gets a reference to a specific model by name.
Gets a mutable reference to a specific model by name.
Example:
if let Some(lstm_model) = nf.get_model("LSTM") {
let metadata = lstm_model.metadata();
println!("LSTM parameters: {}", metadata.parameter_count);
}
// Modify model (if mutable reference needed)
if let Some(lstm_model) = nf.get_model_mut("LSTM") {
lstm_model.reset()?;
}Resets all models to their untrained state.
Example:
// Reset all models
nf.reset()?;
assert!(!nf.is_fitted());Saves all models and metadata to file.
Loads models and metadata from file.
Example:
// Save trained models
nf.save("models.json")?;
// Load models later
let loaded_nf = NeuralForecast::load("models.json")?;The NeuralForecastBuilder provides a fluent API for configuration.
Sets the model ensemble.
Adds a single model to the ensemble.
Sets the time series frequency.
Sets the preprocessing scaler type.
Sets the number of threads for parallel processing.
Configures prediction intervals.
Sets the computation device (CPU/GPU).
Builds the NeuralForecast instance.
use neuro_divergent::{
NeuralForecast, models::{LSTM, NBEATS},
Frequency, ScalerType, Device, PredictionIntervals, IntervalMethod
};
// Create models
let lstm = LSTM::builder()
.hidden_size(128)
.num_layers(2)
.horizon(12)
.input_size(24)
.build()?;
let nbeats = NBEATS::builder()
.stack_types(vec![StackType::Trend, StackType::Seasonality])
.num_blocks(3)
.horizon(12)
.input_size(24)
.build()?;
// Create prediction intervals
let intervals = PredictionIntervals::new(
vec![0.8, 0.9, 0.95],
IntervalMethod::ConformalPrediction
)?;
// Build NeuralForecast instance
let nf = NeuralForecast::builder()
.with_model(Box::new(lstm))
.with_model(Box::new(nbeats))
.with_frequency(Frequency::Monthly)
.with_local_scaler(ScalerType::StandardScaler)
.with_num_threads(4)
.with_prediction_intervals(intervals)
.with_device(Device::CPU)
.build()?;Configuration for training validation.
pub struct ValidationConfig {
pub validation_split: Option<f64>,
pub shuffle: bool,
pub random_seed: Option<u64>,
}
impl ValidationConfig {
pub fn new() -> Self;
pub fn with_validation_split(self, split: f64) -> Self;
pub fn with_shuffle(self, shuffle: bool) -> Self;
pub fn with_random_seed(self, seed: u64) -> Self;
}Configuration for prediction generation.
pub struct PredictionConfig {
pub include_intervals: bool,
pub num_samples: Option<usize>,
pub temperature: Option<f64>,
}
impl PredictionConfig {
pub fn new() -> Self;
pub fn with_intervals(self) -> Self;
pub fn with_num_samples(self, num_samples: usize) -> Self;
pub fn with_temperature(self, temperature: f64) -> Self;
}All methods return NeuroDivergentResult<T> for comprehensive error handling:
- ConfigError: Invalid configuration parameters
- DataError: Data validation or compatibility issues
- TrainingError: Model training failures
- PredictionError: Prediction generation failures
match nf.fit(data) {
Ok(()) => println!("Training successful"),
Err(NeuroDivergentError::TrainingError(msg)) => {
eprintln!("Training failed: {}", msg);
},
Err(NeuroDivergentError::DataError(msg)) => {
eprintln!("Data error: {}", msg);
},
Err(e) => eprintln!("Other error: {}", e),
}- Models are stored as boxed trait objects for flexibility
- Data is processed using Polars for memory efficiency
- Lazy evaluation where possible to minimize memory footprint
// Enable parallel training and prediction
let nf = NeuralForecast::builder()
.with_num_threads(8) // Use 8 threads
.build()?;// Use GPU for compatible models
let nf = NeuralForecast::builder()
.with_device(Device::GPU(0)) // Use first GPU
.build()?;use neuro_divergent::prelude::*;
// 1. Create models
let lstm = LSTM::builder().hidden_size(64).horizon(7).build()?;
let nbeats = NBEATS::builder().num_blocks(2).horizon(7).build()?;
// 2. Create NeuralForecast instance
let mut nf = NeuralForecast::builder()
.with_model(Box::new(lstm))
.with_model(Box::new(nbeats))
.with_frequency(Frequency::Daily)
.build()?;
// 3. Load and prepare data
let data = TimeSeriesDataFrame::from_csv("data.csv")?;
// 4. Train models
nf.fit(data.clone())?;
// 5. Generate forecasts
let forecasts = nf.predict()?;
// 6. Evaluate with cross-validation
let cv_config = CrossValidationConfig::new(3, 7);
let cv_results = nf.cross_validation(data, cv_config)?;// Configure for financial time series
let nf = NeuralForecast::builder()
.with_frequency(Frequency::BusinessDaily)
.with_local_scaler(ScalerType::RobustScaler) // Robust to outliers
.with_prediction_intervals(PredictionIntervals::new(
vec![0.95, 0.99], // High confidence for risk management
IntervalMethod::ConformalPrediction
)?)
.build()?;
// Train on historical financial data
let financial_data = TimeSeriesDataFrame::from_csv("stock_prices.csv")?;
nf.fit(financial_data)?;
// Generate forecasts with confidence intervals
let forecasts = nf.predict()?;
let intervals = forecasts.prediction_intervals()?;// Configure for high-frequency sensor data
let nf = NeuralForecast::builder()
.with_frequency(Frequency::Minute)
.with_num_threads(16) // High parallelism for real-time processing
.with_device(Device::GPU(0)) // GPU acceleration
.build()?;
// Stream processing
let sensor_data = TimeSeriesDataFrame::from_streaming_source()?;
nf.fit(sensor_data)?;
// Real-time prediction
let current_data = get_current_sensor_data()?;
let forecasts = nf.predict_on(current_data)?;NeuralForecast is Send + Sync and can be safely shared across threads:
use std::sync::Arc;
use std::thread;
let nf = Arc::new(fitted_neural_forecast);
let handles: Vec<_> = (0..4).map(|i| {
let nf = Arc::clone(&nf);
thread::spawn(move || {
let data = load_test_data(i)?;
nf.predict_on(data)
})
}).collect();
for handle in handles {
let forecasts = handle.join().unwrap()?;
// Process forecasts
}// Use complementary models for ensemble forecasting
let linear_model = DLinear::builder().horizon(12).build()?;
let nonlinear_model = LSTM::builder().hidden_size(128).horizon(12).build()?;
let interpretable_model = NBEATS::builder().interpretable(true).horizon(12).build()?;
let nf = NeuralForecast::builder()
.with_model(Box::new(linear_model))
.with_model(Box::new(nonlinear_model))
.with_model(Box::new(interpretable_model))
.build()?;// Choose scaler based on data characteristics
let scaler = if data.has_outliers() {
ScalerType::RobustScaler // Robust to outliers
} else if data.is_stationary() {
ScalerType::StandardScaler // Zero mean, unit variance
} else {
ScalerType::MinMaxScaler // Scale to [0, 1]
};
let nf = NeuralForecast::builder()
.with_local_scaler(scaler)
.build()?;// Handle partial training failures
match nf.fit(data) {
Ok(()) => {
// All models trained successfully
},
Err(NeuroDivergentError::TrainingError(msg)) => {
// Some models may have failed
println!("Training issues: {}", msg);
// Check which models are trained
for model_name in nf.model_names() {
if let Some(model) = nf.get_model(&model_name) {
println!("{}: trained = {}", model_name, model.is_trained());
}
}
},
Err(e) => return Err(e),
}The NeuralForecast class provides a comprehensive, user-friendly interface for neural forecasting while maintaining the performance and safety benefits of Rust.