@@ -20,6 +20,8 @@ class RegressionForecaster(BaseForecaster):
20
20
window to form training collection ``X``, take ``horizon`` points ahead to form
21
21
``y``, then apply an aeon or sklearn regressor.
22
22
23
+ If exogenous variables are provided, they are concatenated with the main series
24
+ and included in the regression windows.
23
25
24
26
Parameters
25
27
----------
@@ -36,6 +38,10 @@ class RegressionForecaster(BaseForecaster):
36
38
with sklearn regressors.
37
39
"""
38
40
41
+ _tags = {
42
+ "capability:exogenous" : True ,
43
+ }
44
+
39
45
def __init__ (self , window : int , horizon : int = 1 , regressor = None ):
40
46
self .window = window
41
47
self .regressor = regressor
@@ -52,8 +58,7 @@ def _fit(self, y, exog=None):
52
58
y : np.ndarray
53
59
A time series on which to learn a forecaster to predict horizon ahead.
54
60
exog : np.ndarray, default=None
55
- Optional exogenous time series data. Included for interface
56
- compatibility but ignored in this estimator.
61
+ Optional exogenous time series data, assumed to be aligned with y.
57
62
58
63
Returns
59
64
-------
@@ -65,18 +70,38 @@ def _fit(self, y, exog=None):
65
70
self .regressor_ = LinearRegression ()
66
71
else :
67
72
self .regressor_ = self .regressor
68
- y = y .squeeze ()
69
- if self .window < 1 or self .window > len (y ) - 3 :
73
+
74
+ # Combine y and exog for windowing
75
+ if exog is not None :
76
+ if exog .ndim == 1 :
77
+ exog = exog .reshape (1 , - 1 )
78
+ if exog .shape [1 ] != y .shape [1 ]:
79
+ raise ValueError ("y and exog must have the same number of time points." )
80
+ combined_data = np .vstack ([y , exog ])
81
+ else :
82
+ combined_data = y
83
+
84
+ # Enforce a minimum number of training samples, currently 3
85
+ if self .window < 1 or self .window >= combined_data .shape [1 ] - 3 :
70
86
raise ValueError (
71
- f" window value { self .window } is invalid for series " f"length { len (y )} "
87
+ f"window value { self .window } is invalid for series length "
88
+ f"{ combined_data .shape [1 ]} "
72
89
)
73
- X = np .lib .stride_tricks .sliding_window_view (y , window_shape = self .window )
74
- # Ignore the final horizon values: need to store these for pred with empty y
90
+
91
+ # Create windowed data for X
92
+ X = np .lib .stride_tricks .sliding_window_view (
93
+ combined_data , window_shape = (combined_data .shape [0 ], self .window )
94
+ )
95
+ X = X .squeeze (axis = 0 )
96
+ X = X [:, :, :].reshape (X .shape [0 ], - 1 )
97
+
98
+ # Ignore the final horizon values for X
75
99
X = X [: - self .horizon ]
76
- # Extract y_train
77
- y_train = y [self .window + self .horizon - 1 :]
78
- self .last_ = y [- self .window :]
79
- self .last_ = self .last_ .reshape (1 , - 1 )
100
+
101
+ # Extract y_train from the original series
102
+ y_train = y .squeeze ()[self .window + self .horizon - 1 :]
103
+
104
+ self .last_ = combined_data [:, - self .window :]
80
105
self .regressor_ .fit (X = X , y = y_train )
81
106
return self
82
107
@@ -90,18 +115,33 @@ def _predict(self, y=None, exog=None):
90
115
A time series to predict the next horizon value for. If None,
91
116
predict the next horizon value after series seen in fit.
92
117
exog : np.ndarray, default=None
93
- Optional exogenous time series data. Included for interface
94
- compatibility but ignored in this estimator.
118
+ Optional exogenous time series data, assumed to be aligned with y.
95
119
96
120
Returns
97
121
-------
98
122
float
99
123
single prediction self.horizon steps ahead of y.
100
124
"""
101
125
if y is None :
102
- return self .regressor_ .predict (self .last_ )[0 ]
103
- last = y [:, - self .window :]
104
- return self .regressor_ .predict (last )[0 ]
126
+ # Flatten the last window to be compatible with sklearn regressors
127
+ last_window_flat = self .last_ .reshape (1 , - 1 )
128
+ return self .regressor_ .predict (last_window_flat )[0 ]
129
+
130
+ # Combine y and exog for prediction
131
+ if exog is not None :
132
+ if exog .ndim == 1 :
133
+ exog = exog .reshape (1 , - 1 )
134
+ if exog .shape [1 ] != y .shape [1 ]:
135
+ raise ValueError ("y and exog must have the same number of time points." )
136
+ combined_data = np .vstack ([y , exog ])
137
+ else :
138
+ combined_data = y
139
+
140
+ # Extract the last window and flatten for prediction
141
+ last_window = combined_data [:, - self .window :]
142
+ last_window_flat = last_window .reshape (1 , - 1 )
143
+
144
+ return self .regressor_ .predict (last_window_flat )[0 ]
105
145
106
146
@classmethod
107
147
def _get_test_params (cls , parameter_set : str = "default" ):
0 commit comments