1- """
2- Example script demonstrating MultiOutputMTS usage
3- """
4-
1+ import nnetsauce as ns
52import numpy as np
63import pandas as pd
7- import matplotlib .pyplot as plt
8- import time
9- from sklearn .linear_model import Ridge , LinearRegression
10- from sklearn .ensemble import RandomForestRegressor
11- from sklearn .multioutput import MultiOutputRegressor
12-
13- # Import the class (assuming it's in your Python path)
14- try :
15- import nnetsauce as ns
16- print ("Successfully imported nnetsauce" )
17- except ImportError :
18- print ("Creating a dummy class for demonstration" )
19- # For demonstration, we'll use the class definition above
20- # In practice, you would import from nnetsauce
21-
22-
23- def create_sample_data (n_samples = 200 , n_series = 3 , noise = 0.1 , trend = True ):
24- """Create correlated multivariate time series."""
25- np .random .seed (42 )
26-
27- # Base trend
28- if trend :
29- base_trend = np .linspace (0 , 10 , n_samples )
30- else :
31- base_trend = np .zeros (n_samples )
32-
33- # Create series with correlations
34- series_data = np .zeros ((n_samples , n_series ))
35-
36- for i in range (n_series ):
37- # Each series has: base trend + seasonal pattern + noise + series-specific offset
38- seasonal = 2 * np .sin (2 * np .pi * np .arange (n_samples ) / 50 + i * np .pi / 3 )
39- noise_component = noise * np .random .randn (n_samples )
40- series_data [:, i ] = base_trend + seasonal + noise_component + i * 5
41-
42- # Add some cross-correlation
43- for i in range (1 , n_series ):
44- series_data [:, i ] += 0.3 * series_data [:, i - 1 ]
45-
46- # Create DataFrame with dates
47- dates = pd .date_range ('2020-01-01' , periods = n_samples , freq = 'D' )
48- df = pd .DataFrame (series_data ,
49- columns = [f'Series_{ i } ' for i in range (n_series )],
50- index = dates )
51-
52- return df
53-
54-
55- def example_1_native_multioutput ():
56- """Example 1: Using Ridge regression (native multioutput support)."""
57- print ("\n " + "=" * 60 )
58- print ("EXAMPLE 1: Ridge Regression (Native Multioutput)" )
59- print ("=" * 60 )
60-
61- # Create sample data
62- df = create_sample_data (n_samples = 150 , n_series = 3 )
63- print (f"Data shape: { df .shape } " )
64- print (f"Columns: { df .columns .tolist ()} " )
65-
66- # Create Ridge regressor
67- ridge = Ridge (alpha = 1.0 , random_state = 42 )
68-
69- # Create MultiOutputMTS model
70- model = ns .MultiOutputMTS (
71- obj = ridge ,
72- lags = 15 ,
73- n_hidden_features = 15 ,
74- type_pi = 'kde' ,
75- replications = 200 ,
76- kernel = 'gaussian' ,
77- seed = 42 ,
78- verbose = 1
79- )
80-
81- # Fit the model
82- print ("\n Fitting model..." )
83- start_time = time .time ()
84- model .fit (df )
85- fit_time = time .time () - start_time
86- print (f"Fitting completed in { fit_time :.2f} seconds" )
87-
88- # Get multioutput info
89- info = model .get_multioutput_info ()
90- print (f"\n Multioutput info:" )
91- for key , value in info .items ():
92- print (f" { key } : { value } " )
93-
94- # Make predictions
95- print ("\n Making 30-day forecasts with 95% prediction intervals..." )
96- forecast = model .predict (h = 30 , level = 95 )
97-
98- print (f"\n Point forecasts shape: { forecast .mean .shape } " )
99- print ("\n First 5 forecast periods:" )
100- print (forecast .mean .head ())
101-
102- print ("\n Prediction intervals (first period):" )
103- for i , series in enumerate (df .columns ):
104- print (f" { series } : { forecast .lower .iloc [0 , i ]:.2f} < { forecast .mean .iloc [0 , i ]:.2f} < { forecast .upper .iloc [0 , i ]:.2f} " )
105-
106- return model , df , forecast
107-
108-
109- def example_2_wrapped_non_multioutput ():
110- """Example 2: Using RandomForest with MultiOutputRegressor wrapper."""
111- print ("\n " + "=" * 60 )
112- print ("EXAMPLE 2: RandomForest with MultiOutputRegressor Wrapper" )
113- print ("=" * 60 )
114-
115- df = create_sample_data (n_samples = 100 , n_series = 2 )
116-
117- # Create RandomForest (not natively multioutput)
118- rf = RandomForestRegressor (n_estimators = 50 , max_depth = 5 , random_state = 42 )
119-
120- # Wrap it for multioutput support
121- multi_rf = MultiOutputRegressor (rf )
122-
123- # Create model
124- model = ns .MultiOutputMTS (
125- obj = multi_rf ,
126- lags = 15 ,
127- n_hidden_features = 10 ,
128- type_pi = 'gaussian' ,
129- verbose = 1
130- )
131-
132- print ("Fitting model..." )
133- model .fit (df )
134-
135- # Make predictions
136- forecast = model .predict (h = 20 , level = 90 )
137-
138- print (f"\n Forecast shape: { forecast .mean .shape } " )
139- print ("\n Model info:" )
140- info = model .get_multioutput_info ()
141- for key , value in info .items ():
142- print (f" { key } : { value } " )
143-
144- return model , df , forecast
145-
146-
147- def example_3_performance_comparison ():
148- """Example 3: Performance comparison between MTS and MultiOutputMTS."""
149- print ("\n " + "=" * 60 )
150- print ("EXAMPLE 3: Performance Comparison" )
151- print ("=" * 60 )
152-
153- # Create larger dataset for performance test
154- df = create_sample_data (n_samples = 500 , n_series = 5 )
155-
156- # Test with Ridge (native multioutput)
157- ridge = Ridge (alpha = 1.0 )
158-
159- # Regular MTS
160- print ("\n Testing Regular MTS (loop-based)..." )
161- start = time .time ()
162- model_regular = ns .MTS (
163- obj = ridge ,
164- lags = 15 ,
165- n_hidden_features = 10 ,
166- type_pi = 'gaussian' ,
167- verbose = 0
168- )
169- model_regular .fit (df )
170- regular_time = time .time () - start
171- print (f"Regular MTS fitting time: { regular_time :.4f} seconds" )
172-
173- # MultiOutputMTS
174- print ("\n Testing MultiOutputMTS..." )
175- start = time .time ()
176- model_multi = ns .MultiOutputMTS (
177- obj = ridge ,
178- lags = 15 ,
179- n_hidden_features = 10 ,
180- type_pi = 'gaussian' ,
181- verbose = 0
182- )
183- model_multi .fit (df )
184- multi_time = time .time () - start
185- print (f"MultiOutputMTS fitting time: { multi_time :.4f} seconds" )
186-
187- print (f"\n Speedup: { regular_time / multi_time :.2f} x faster" )
188-
189- # Compare predictions
190- forecast_regular = model_regular .predict (h = 10 )
191- forecast_multi = model_multi .predict (h = 10 )
192-
193- print ("\n Prediction comparison (RMSE between methods):" )
194- for i , series in enumerate (df .columns ):
195- diff = np .sqrt (np .mean ((forecast_regular .mean .iloc [:, i ] - forecast_multi .mean .iloc [:, i ])** 2 ))
196- print (f" { series } : { diff :.6f} " )
197-
198- return regular_time , multi_time
199-
200-
201- def example_4_quantile_forecasts ():
202- """Example 4: Quantile forecasts."""
203- print ("\n " + "=" * 60 )
204- print ("EXAMPLE 4: Quantile Forecasts" )
205- print ("=" * 60 )
206-
207- df = create_sample_data (n_samples = 120 , n_series = 2 )
208-
209- # For quantile regression, we need a quantile-compatible model
210- from sklearn .linear_model import LinearRegression
211-
212- lr = LinearRegression ()
213-
214- model = ns .MultiOutputMTS (
215- obj = lr ,
216- lags = 15 ,
217- n_hidden_features = 12 ,
218- type_pi = 'kde' , # Using KDE for quantile simulation
219- replications = 500 ,
220- verbose = 1
221- )
222-
223- model .fit (df )
224-
225- # Predict specific quantiles
226- quantiles = [0.05 , 0.25 , 0.5 , 0.75 , 0.95 ]
227- print (f"\n Predicting quantiles: { quantiles } " )
228-
229- quantile_forecast = model .predict (h = 20 , quantiles = quantiles )
230-
231- print (f"\n Quantile forecast columns: { quantile_forecast .columns .tolist ()} " )
232- print ("\n First forecast period:" )
233- print (quantile_forecast .iloc [0 ].round (2 ))
234-
235- return model , df , quantile_forecast
236-
237-
238- def example_5_visualization (model , df , forecast ):
239- """Example 5: Visualization of results."""
240- print ("\n " + "=" * 60 )
241- print ("EXAMPLE 5: Visualization" )
242- print ("=" * 60 )
243-
244- # Plot each series
245- fig , axes = plt .subplots (len (df .columns ), 1 , figsize = (12 , 4 * len (df .columns )))
246- if len (df .columns ) == 1 :
247- axes = [axes ]
248-
249- for idx , (ax , series_name ) in enumerate (zip (axes , df .columns )):
250- # Historical data
251- ax .plot (df .index , df [series_name ], 'b-' , label = 'Historical' , linewidth = 2 )
252-
253- # Forecast
254- forecast_dates = forecast .mean .index
255- ax .plot (forecast_dates , forecast .mean [series_name ], 'r-' , label = 'Forecast' , linewidth = 2 )
256-
257- # Prediction intervals
258- ax .fill_between (
259- forecast_dates ,
260- forecast .lower [series_name ],
261- forecast .upper [series_name ],
262- alpha = 0.2 , color = 'red' , label = f'{ model .level_ } % Prediction Interval'
263- )
264-
265- # Add vertical line at forecast start
266- ax .axvline (x = df .index [- 1 ], color = 'gray' , linestyle = '--' , alpha = 0.5 )
267-
268- ax .set_title (f'{ series_name } - 30-Day Forecast' )
269- ax .set_xlabel ('Date' )
270- ax .set_ylabel ('Value' )
271- ax .legend ()
272- ax .grid (True , alpha = 0.3 )
273-
274- plt .tight_layout ()
275- plt .savefig ('multioutput_mts_forecast.png' , dpi = 150 , bbox_inches = 'tight' )
276- print ("Plot saved as 'multioutput_mts_forecast.png'" )
277- plt .show ()
278-
279- # Spaghetti plot for first series if simulations available
280- if hasattr (forecast , 'sims' ) and forecast .sims is not None :
281- fig , ax = plt .subplots (figsize = (12 , 6 ))
282-
283- # Plot historical
284- ax .plot (df .index , df .iloc [:, 0 ], 'b-' , label = 'Historical' , linewidth = 2 )
285-
286- # Plot a sample of simulations
287- n_sims_to_plot = min (20 , len (forecast .sims ))
288- for i in range (n_sims_to_plot ):
289- ax .plot (forecast .mean .index , forecast .sims [i ].iloc [:, 0 ],
290- alpha = 0.1 , color = 'red' )
291-
292- # Plot mean forecast
293- ax .plot (forecast .mean .index , forecast .mean .iloc [:, 0 ],
294- 'r-' , label = 'Mean Forecast' , linewidth = 2 )
295-
296- ax .axvline (x = df .index [- 1 ], color = 'gray' , linestyle = '--' , alpha = 0.5 )
297- ax .set_title (f'{ df .columns [0 ]} - Spaghetti Plot ({ n_sims_to_plot } simulations)' )
298- ax .set_xlabel ('Date' )
299- ax .set_ylabel ('Value' )
300- ax .legend ()
301- ax .grid (True , alpha = 0.3 )
302-
303- plt .tight_layout ()
304- plt .savefig ('multioutput_mts_spaghetti.png' , dpi = 150 , bbox_inches = 'tight' )
305- print ("Spaghetti plot saved as 'multioutput_mts_spaghetti.png'" )
306- plt .show ()
307-
308-
309- # ============================================================
310- # MAIN EXECUTION
311- # ============================================================
312- if __name__ == "__main__" :
313- # Run examples and capture returns
314- print ("\n Running MultiOutputMTS Examples..." )
315- print ("=" * 60 )
316-
317- # Example 1: Ridge with KDE intervals
318- model1 , df1 , forecast1 = example_1_native_multioutput ()
319-
320- # Example 2: RandomForest with Gaussian intervals
321- model2 , df2 , forecast2 = example_2_wrapped_non_multioutput ()
322-
323- # Example 3: Performance comparison
324- regular_time , multi_time = example_3_performance_comparison ()
325-
326- # Example 4: Quantile forecasts
327- model4 , df4 , quantile_forecast = example_4_quantile_forecasts ()
328-
329- # Example 5: Visualization (using results from Example 1)
330- example_5_visualization (model1 , df1 , forecast1 )
331-
332- print ("\n " + "=" * 60 )
333- print ("All examples completed successfully!" )
334- print ("=" * 60 )
335- print (f"\n Summary:" )
336- print (f" - Example 1: Ridge regression with KDE intervals" )
337- print (f" - Example 2: RandomForest with Gaussian intervals" )
338- print (f" - Example 3: Speedup = { regular_time / multi_time :.2f} x" )
339- print (f" - Example 4: Quantile forecasts generated" )
340- print (f" - Example 5: Visualizations saved" )
4+ from sklearn .linear_model import Ridge
5+
6+ # Create sample multivariate time series (3 series, 100 observations)
7+ np .random .seed (42 )
8+ n_obs = 100
9+ data = {
10+ 'sales' : np .cumsum (np .random .randn (n_obs )) + 100 ,
11+ 'revenue' : np .cumsum (np .random .randn (n_obs )) + 500 ,
12+ 'orders' : np .cumsum (np .random .randn (n_obs )) + 50
13+ }
14+ df = pd .DataFrame (data )
15+
16+ print ("Data shape:" , df .shape )
17+ print ("\n First 5 rows:" )
18+ print (df .head ())
19+
20+ # Fit MultivariateMTS with vectorized Ridge
21+ model = ns .MultiOutputMTS (
22+ obj = Ridge (alpha = 1.0 ),
23+ lags = 3 ,
24+ n_hidden_features = 10 ,
25+ type_pi = 'bootstrap' ,
26+ replications = 100 ,
27+ verbose = 1 ,
28+ show_progress = False
29+ )
30+
31+ # Fit model
32+ model .fit (df )
33+
34+ # Predict 10 steps ahead with 95% prediction intervals
35+ forecast = model .predict (h = 10 , level = 95 )
36+ print ("forecast:" , forecast )
37+ print ("\n " + "=" * 60 )
38+ print ("FORECAST RESULTS" )
39+ print ("=" * 60 )
40+ print ("\n Mean predictions:" )
41+ print (forecast .mean )
42+ print ("\n Lower bounds (95%):" )
43+ print (forecast .lower )
44+ print ("\n Upper bounds (95%):" )
45+ print (forecast .upper )
46+
47+ # Predict specific quantiles
48+ quantile_forecast = model .predict (h = 10 , quantiles = [0.1 , 0.5 , 0.9 ])
49+ print ("\n " + "=" * 60 )
50+ print ("QUANTILE PREDICTIONS" )
51+ print ("=" * 60 )
52+ print (quantile_forecast )
0 commit comments