Coverage for /home/martinb/.local/share/virtualenvs/camcops/lib/python3.6/site-packages/statsmodels/tsa/arima/params.py : 18%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1"""
2SARIMAX parameters class.
4Author: Chad Fulton
5License: BSD-3
6"""
7import numpy as np
8import pandas as pd
9from numpy.polynomial import Polynomial
11from statsmodels.tsa.statespace.tools import is_invertible
12from statsmodels.tsa.arima.tools import validate_basic
15class SARIMAXParams(object):
16 """
17 SARIMAX parameters.
19 Parameters
20 ----------
21 spec : SARIMAXSpecification
22 Specification of the SARIMAX model.
24 Attributes
25 ----------
26 spec : SARIMAXSpecification
27 Specification of the SARIMAX model.
28 exog_names : list of str
29 Names associated with exogenous parameters.
30 ar_names : list of str
31 Names associated with (non-seasonal) autoregressive parameters.
32 ma_names : list of str
33 Names associated with (non-seasonal) moving average parameters.
34 seasonal_ar_names : list of str
35 Names associated with seasonal autoregressive parameters.
36 seasonal_ma_names : list of str
37 Names associated with seasonal moving average parameters.
38 param_names :list of str
39 Names of all model parameters.
40 k_exog_params : int
41 Number of parameters associated with exogenous variables.
42 k_ar_params : int
43 Number of parameters associated with (non-seasonal) autoregressive
44 lags.
45 k_ma_params : int
46 Number of parameters associated with (non-seasonal) moving average
47 lags.
48 k_seasonal_ar_params : int
49 Number of parameters associated with seasonal autoregressive lags.
50 k_seasonal_ma_params : int
51 Number of parameters associated with seasonal moving average lags.
52 k_params : int
53 Total number of model parameters.
54 """
56 def __init__(self, spec):
57 self.spec = spec
59 # Local copies of relevant attributes
60 self.exog_names = spec.exog_names
61 self.ar_names = spec.ar_names
62 self.ma_names = spec.ma_names
63 self.seasonal_ar_names = spec.seasonal_ar_names
64 self.seasonal_ma_names = spec.seasonal_ma_names
65 self.param_names = spec.param_names
67 self.k_exog_params = spec.k_exog_params
68 self.k_ar_params = spec.k_ar_params
69 self.k_ma_params = spec.k_ma_params
70 self.k_seasonal_ar_params = spec.k_seasonal_ar_params
71 self.k_seasonal_ma_params = spec.k_seasonal_ma_params
72 self.k_params = spec.k_params
74 # Cache for holding parameter values
75 self._params_split = spec.split_params(
76 np.zeros(self.k_params) * np.nan, allow_infnan=True)
77 self._params = None
79 @property
80 def exog_params(self):
81 """(array) Parameters associated with exogenous variables."""
82 return self._params_split['exog_params']
84 @exog_params.setter
85 def exog_params(self, value):
86 if np.isscalar(value):
87 value = [value] * self.k_exog_params
88 self._params_split['exog_params'] = validate_basic(
89 value, self.k_exog_params, title='exogenous coefficients')
90 self._params = None
92 @property
93 def ar_params(self):
94 """(array) Autoregressive (non-seasonal) parameters."""
95 return self._params_split['ar_params']
97 @ar_params.setter
98 def ar_params(self, value):
99 if np.isscalar(value):
100 value = [value] * self.k_ar_params
101 self._params_split['ar_params'] = validate_basic(
102 value, self.k_ar_params, title='AR coefficients')
103 self._params = None
105 @property
106 def ar_poly(self):
107 """(Polynomial) Autoregressive (non-seasonal) lag polynomial."""
108 coef = np.zeros(self.spec.max_ar_order + 1)
109 coef[0] = 1
110 ix = self.spec.ar_lags
111 coef[ix] = -self._params_split['ar_params']
112 return Polynomial(coef)
114 @ar_poly.setter
115 def ar_poly(self, value):
116 # Convert from the polynomial to the parameters, and set that way
117 if isinstance(value, Polynomial):
118 value = value.coef
119 value = validate_basic(value, self.spec.max_ar_order + 1,
120 title='AR polynomial')
121 if value[0] != 1:
122 raise ValueError('AR polynomial constant must be equal to 1.')
123 ar_params = []
124 for i in range(1, self.spec.max_ar_order + 1):
125 if i in self.spec.ar_lags:
126 ar_params.append(-value[i])
127 elif value[i] != 0:
128 raise ValueError('AR polynomial includes non-zero values'
129 ' for lags that are excluded in the'
130 ' specification.')
131 self.ar_params = ar_params
133 @property
134 def ma_params(self):
135 """(array) Moving average (non-seasonal) parameters."""
136 return self._params_split['ma_params']
138 @ma_params.setter
139 def ma_params(self, value):
140 if np.isscalar(value):
141 value = [value] * self.k_ma_params
142 self._params_split['ma_params'] = validate_basic(
143 value, self.k_ma_params, title='MA coefficients')
144 self._params = None
146 @property
147 def ma_poly(self):
148 """(Polynomial) Moving average (non-seasonal) lag polynomial."""
149 coef = np.zeros(self.spec.max_ma_order + 1)
150 coef[0] = 1
151 ix = self.spec.ma_lags
152 coef[ix] = self._params_split['ma_params']
153 return Polynomial(coef)
155 @ma_poly.setter
156 def ma_poly(self, value):
157 # Convert from the polynomial to the parameters, and set that way
158 if isinstance(value, Polynomial):
159 value = value.coef
160 value = validate_basic(value, self.spec.max_ma_order + 1,
161 title='MA polynomial')
162 if value[0] != 1:
163 raise ValueError('MA polynomial constant must be equal to 1.')
164 ma_params = []
165 for i in range(1, self.spec.max_ma_order + 1):
166 if i in self.spec.ma_lags:
167 ma_params.append(value[i])
168 elif value[i] != 0:
169 raise ValueError('MA polynomial includes non-zero values'
170 ' for lags that are excluded in the'
171 ' specification.')
172 self.ma_params = ma_params
174 @property
175 def seasonal_ar_params(self):
176 """(array) Seasonal autoregressive parameters."""
177 return self._params_split['seasonal_ar_params']
179 @seasonal_ar_params.setter
180 def seasonal_ar_params(self, value):
181 if np.isscalar(value):
182 value = [value] * self.k_seasonal_ar_params
183 self._params_split['seasonal_ar_params'] = validate_basic(
184 value, self.k_seasonal_ar_params, title='seasonal AR coefficients')
185 self._params = None
187 @property
188 def seasonal_ar_poly(self):
189 """(Polynomial) Seasonal autoregressive lag polynomial."""
190 # Need to expand the polynomial according to the season
191 s = self.spec.seasonal_periods
192 coef = [1]
193 if s > 0:
194 expanded = np.zeros(self.spec.max_seasonal_ar_order)
195 ix = np.array(self.spec.seasonal_ar_lags, dtype=int) - 1
196 expanded[ix] = -self._params_split['seasonal_ar_params']
197 coef = np.r_[1, np.pad(np.reshape(expanded, (-1, 1)),
198 [(0, 0), (s - 1, 0)], 'constant').flatten()]
199 return Polynomial(coef)
201 @seasonal_ar_poly.setter
202 def seasonal_ar_poly(self, value):
203 s = self.spec.seasonal_periods
204 # Note: assume that we are given coefficients from the full polynomial
205 # Convert from the polynomial to the parameters, and set that way
206 if isinstance(value, Polynomial):
207 value = value.coef
208 value = validate_basic(value, 1 + s * self.spec.max_seasonal_ar_order,
209 title='seasonal AR polynomial')
210 if value[0] != 1:
211 raise ValueError('Polynomial constant must be equal to 1.')
212 seasonal_ar_params = []
213 for i in range(1, self.spec.max_seasonal_ar_order + 1):
214 if i in self.spec.seasonal_ar_lags:
215 seasonal_ar_params.append(-value[s * i])
216 elif value[s * i] != 0:
217 raise ValueError('AR polynomial includes non-zero values'
218 ' for lags that are excluded in the'
219 ' specification.')
220 self.seasonal_ar_params = seasonal_ar_params
222 @property
223 def seasonal_ma_params(self):
224 """(array) Seasonal moving average parameters."""
225 return self._params_split['seasonal_ma_params']
227 @seasonal_ma_params.setter
228 def seasonal_ma_params(self, value):
229 if np.isscalar(value):
230 value = [value] * self.k_seasonal_ma_params
231 self._params_split['seasonal_ma_params'] = validate_basic(
232 value, self.k_seasonal_ma_params, title='seasonal MA coefficients')
233 self._params = None
235 @property
236 def seasonal_ma_poly(self):
237 """(Polynomial) Seasonal moving average lag polynomial."""
238 # Need to expand the polynomial according to the season
239 s = self.spec.seasonal_periods
240 coef = np.array([1])
241 if s > 0:
242 expanded = np.zeros(self.spec.max_seasonal_ma_order)
243 ix = np.array(self.spec.seasonal_ma_lags, dtype=int) - 1
244 expanded[ix] = self._params_split['seasonal_ma_params']
245 coef = np.r_[1, np.pad(np.reshape(expanded, (-1, 1)),
246 [(0, 0), (s - 1, 0)], 'constant').flatten()]
247 return Polynomial(coef)
249 @seasonal_ma_poly.setter
250 def seasonal_ma_poly(self, value):
251 s = self.spec.seasonal_periods
252 # Note: assume that we are given coefficients from the full polynomial
253 # Convert from the polynomial to the parameters, and set that way
254 if isinstance(value, Polynomial):
255 value = value.coef
256 value = validate_basic(value, 1 + s * self.spec.max_seasonal_ma_order,
257 title='seasonal MA polynomial',)
258 if value[0] != 1:
259 raise ValueError('Polynomial constant must be equal to 1.')
260 seasonal_ma_params = []
261 for i in range(1, self.spec.max_seasonal_ma_order + 1):
262 if i in self.spec.seasonal_ma_lags:
263 seasonal_ma_params.append(value[s * i])
264 elif value[s * i] != 0:
265 raise ValueError('MA polynomial includes non-zero values'
266 ' for lags that are excluded in the'
267 ' specification.')
268 self.seasonal_ma_params = seasonal_ma_params
270 @property
271 def sigma2(self):
272 """(float) Innovation variance."""
273 return self._params_split['sigma2']
275 @sigma2.setter
276 def sigma2(self, params):
277 length = int(not self.spec.concentrate_scale)
278 self._params_split['sigma2'] = validate_basic(
279 params, length, title='sigma2').item()
280 self._params = None
282 @property
283 def reduced_ar_poly(self):
284 """(Polynomial) Reduced form autoregressive lag polynomial."""
285 return self.ar_poly * self.seasonal_ar_poly
287 @property
288 def reduced_ma_poly(self):
289 """(Polynomial) Reduced form moving average lag polynomial."""
290 return self.ma_poly * self.seasonal_ma_poly
292 @property
293 def params(self):
294 """(array) Complete parameter vector."""
295 if self._params is None:
296 self._params = self.spec.join_params(**self._params_split)
297 return self._params.copy()
299 @params.setter
300 def params(self, value):
301 self._params_split = self.spec.split_params(value)
302 self._params = None
304 @property
305 def is_complete(self):
306 """(bool) Are current parameter values all filled in (i.e. not NaN)."""
307 return not np.any(np.isnan(self.params))
309 @property
310 def is_valid(self):
311 """(bool) Are current parameter values valid (e.g. variance > 0)."""
312 valid = True
313 try:
314 self.spec.validate_params(self.params)
315 except ValueError:
316 valid = False
317 return valid
319 @property
320 def is_stationary(self):
321 """(bool) Is the reduced autoregressive lag poylnomial stationary."""
322 validate_basic(self.ar_params, self.k_ar_params,
323 title='AR coefficients')
324 validate_basic(self.seasonal_ar_params, self.k_seasonal_ar_params,
325 title='seasonal AR coefficients')
327 ar_stationary = True
328 seasonal_ar_stationary = True
329 if self.k_ar_params > 0:
330 ar_stationary = is_invertible(self.ar_poly.coef)
331 if self.k_seasonal_ar_params > 0:
332 seasonal_ar_stationary = is_invertible(self.seasonal_ar_poly.coef)
334 return ar_stationary and seasonal_ar_stationary
336 @property
337 def is_invertible(self):
338 """(bool) Is the reduced moving average lag poylnomial invertible."""
339 # Short-circuit if there is no MA component
340 validate_basic(self.ma_params, self.k_ma_params,
341 title='MA coefficients')
342 validate_basic(self.seasonal_ma_params, self.k_seasonal_ma_params,
343 title='seasonal MA coefficients')
345 ma_stationary = True
346 seasonal_ma_stationary = True
347 if self.k_ma_params > 0:
348 ma_stationary = is_invertible(self.ma_poly.coef)
349 if self.k_seasonal_ma_params > 0:
350 seasonal_ma_stationary = is_invertible(self.seasonal_ma_poly.coef)
352 return ma_stationary and seasonal_ma_stationary
354 def to_dict(self):
355 """
356 Return the parameters split by type into a dictionary.
358 Returns
359 -------
360 split_params : dict
361 Dictionary with keys 'exog_params', 'ar_params', 'ma_params',
362 'seasonal_ar_params', 'seasonal_ma_params', and (unless
363 `concentrate_scale=True`) 'sigma2'. Values are the parameters
364 associated with the key, based on the `params` argument.
365 """
366 return self._params_split.copy()
368 def to_pandas(self):
369 """
370 Return the parameters as a Pandas series.
372 Returns
373 -------
374 series : pd.Series
375 Pandas series with index set to the parameter names.
376 """
377 return pd.Series(self.params, index=self.param_names)
379 def __repr__(self):
380 """Represent SARIMAXParams object as a string."""
381 components = []
382 if self.k_exog_params:
383 components.append('exog=%s' % str(self.exog_params))
384 if self.k_ar_params:
385 components.append('ar=%s' % str(self.ar_params))
386 if self.k_ma_params:
387 components.append('ma=%s' % str(self.ma_params))
388 if self.k_seasonal_ar_params:
389 components.append('seasonal_ar=%s' %
390 str(self.seasonal_ar_params))
391 if self.k_seasonal_ma_params:
392 components.append('seasonal_ma=%s' %
393 str(self.seasonal_ma_params))
394 if not self.spec.concentrate_scale:
395 components.append('sigma2=%s' % self.sigma2)
396 return 'SARIMAXParams(%s)' % ', '.join(components)