timeseries-toolbox 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- timeseries-toolbox-0.1.0/LICENSE +21 -0
- timeseries-toolbox-0.1.0/PKG-INFO +402 -0
- timeseries-toolbox-0.1.0/README.md +355 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/PyFiles/01_ARMA_Model.py +267 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/PyFiles/02_ARIMA_Model.py +296 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/PyFiles/03_Seasonal_ARIMA_Model.py +366 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/PyFiles/04_BJTF_Model.py +663 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/PyFiles/__init__.py +0 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Examples/__init__.py +0 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/QAModel.py +620 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/__init__.py +22 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/estimate.py +104 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/estimlm.py +337 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/jacobian.py +102 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/model.py +1149 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/pmodaic.py +74 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/pmodbic.py +75 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/pmoddisp.py +271 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/pmodmse.py +66 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/pmodsim.py +151 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/Model/selpmod.py +389 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_A_Chemical_Concentration.csv +198 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_B1_IBM_Stock_Daily.csv +256 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_B_IBM_Stock.csv +370 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_C_Chemical_Temperature.csv +227 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_D_Chemical_Viscosity.csv +311 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_E_Sunspot_Numbers.csv +101 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_F_Chemical_Yields.csv +71 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_G_Airline_Passengers.csv +145 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TestData/Series_J_Gas_Furnace.csv +297 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TimeSeries/QAscript.py +100 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TimeSeries/TSAnalysis.py +82 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/TimeSeries/__init__.py +11 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/__init__.py +68 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/__init__.py +0 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/calcindex.py +69 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/chisqrdf.py +42 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/cliprec.py +27 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/gcombvec.py +82 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/gpac.py +94 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/impest.py +72 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/makerow.py +36 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/multiAnal.py +170 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/multiChi.py +144 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/newrec.py +38 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/parcor.py +63 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/partoacf.py +205 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/plotacf.py +96 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/plotgpac.py +134 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/sdiff.py +67 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/sepym.py +64 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/uniAnal.py +162 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/uniChi.py +86 -0
- timeseries-toolbox-0.1.0/TimeSeriesSRC/basefunctions/xcorr.py +95 -0
- timeseries-toolbox-0.1.0/pyproject.toml +80 -0
- timeseries-toolbox-0.1.0/setup.cfg +4 -0
- timeseries-toolbox-0.1.0/setup.py +4 -0
- timeseries-toolbox-0.1.0/tests/test_basefunctions.py +141 -0
- timeseries-toolbox-0.1.0/tests/test_models.py +138 -0
- timeseries-toolbox-0.1.0/timeseries_toolbox.egg-info/PKG-INFO +402 -0
- timeseries-toolbox-0.1.0/timeseries_toolbox.egg-info/SOURCES.txt +62 -0
- timeseries-toolbox-0.1.0/timeseries_toolbox.egg-info/dependency_links.txt +1 -0
- timeseries-toolbox-0.1.0/timeseries_toolbox.egg-info/requires.txt +16 -0
- timeseries-toolbox-0.1.0/timeseries_toolbox.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Amir Jafari, Martin Hagan, Lilian S. De Rivera
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,402 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: timeseries-toolbox
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: A Python toolbox for time series analysis and prediction modeling based on the Box-Jenkins framework
|
|
5
|
+
Author: Martin Hagan, Lilian S. De Rivera
|
|
6
|
+
Author-email: Amir Jafari <ajafari@gwu.edu>
|
|
7
|
+
Maintainer-email: Amir Jafari <ajafari@gwu.edu>
|
|
8
|
+
License: MIT
|
|
9
|
+
Project-URL: Homepage, https://github.com/amir-jafari/TimeSeries
|
|
10
|
+
Project-URL: Documentation, https://amir-jafari.github.io/TimeSeries
|
|
11
|
+
Project-URL: User Guide, https://amir-jafari.github.io/TimeSeries/UserGuide.html
|
|
12
|
+
Project-URL: Repository, https://github.com/amir-jafari/TimeSeries
|
|
13
|
+
Project-URL: Bug Tracker, https://github.com/amir-jafari/TimeSeries/issues
|
|
14
|
+
Project-URL: Changelog, https://github.com/amir-jafari/TimeSeries/releases
|
|
15
|
+
Keywords: time series,ARMA,ARIMA,ARMAX,ARX,BJTF,Box-Jenkins,system identification,forecasting,Levenberg-Marquardt,model selection,AIC,BIC
|
|
16
|
+
Classifier: Development Status :: 3 - Alpha
|
|
17
|
+
Classifier: Intended Audience :: Science/Research
|
|
18
|
+
Classifier: Intended Audience :: Education
|
|
19
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
20
|
+
Classifier: Programming Language :: Python :: 3
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
24
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
25
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
26
|
+
Classifier: Topic :: Scientific/Engineering
|
|
27
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
|
28
|
+
Classifier: Topic :: Scientific/Engineering :: Information Analysis
|
|
29
|
+
Classifier: Operating System :: OS Independent
|
|
30
|
+
Requires-Python: >=3.8
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
License-File: LICENSE
|
|
33
|
+
Requires-Dist: numpy>=1.19
|
|
34
|
+
Requires-Dist: scipy>=1.5
|
|
35
|
+
Requires-Dist: matplotlib>=3.3
|
|
36
|
+
Provides-Extra: dev
|
|
37
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: sphinx>=7.0; extra == "docs"
|
|
41
|
+
Requires-Dist: furo>=2023.1.1; extra == "docs"
|
|
42
|
+
Requires-Dist: sphinx-copybutton>=0.5; extra == "docs"
|
|
43
|
+
Requires-Dist: myst-parser>=2.0; extra == "docs"
|
|
44
|
+
Requires-Dist: sphinx-autodoc-typehints>=1.23; extra == "docs"
|
|
45
|
+
Requires-Dist: nbsphinx>=0.9; extra == "docs"
|
|
46
|
+
Requires-Dist: ipykernel>=6.0; extra == "docs"
|
|
47
|
+
|
|
48
|
+
# TimeSeriesSRC
|
|
49
|
+
|
|
50
|
+
A Python toolbox for time series analysis and prediction modeling, based on the classical framework of **Box and Jenkins** (*Time Series Analysis: Forecasting and Control*) and **Ljung** (*System Identification: Theory for the User*).
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## System Identification Process
|
|
55
|
+
|
|
56
|
+
Building a prediction model is an iterative four-step process.
|
|
57
|
+
|
|
58
|
+
<p align="center">
|
|
59
|
+
<img src="docs/SysId_Process.svg" alt="System Identification Process" width="220">
|
|
60
|
+
</p>
|
|
61
|
+
|
|
62
|
+
**1. Choose a model class.** Select the family of models appropriate for your data and application — for example, ARMA for a univariate series with no external input, ARX or ARMAX when an input is available but the model structure should be simple, or BJTF when the input dynamics and noise model need to be identified independently. The choice is guided by physical knowledge of the system and by preliminary data analysis.
|
|
63
|
+
|
|
64
|
+
**2. Select model order.** Determine the polynomial orders ($n_a$, $n_b$, $n_c$, $n_d$, $n_f$) and the input delay $k$. The toolbox provides `uniAnal` and `multiAnal` to compute the ACF, PACF, GPAC, and impulse response — the standard tools for reading off candidate orders from data. `selpmod` automates this step by fitting a grid of structures and selecting the best by AIC or BIC.
|
|
65
|
+
|
|
66
|
+
**3. Estimate parameters.** Fit the chosen model structure to data using `estimate`, which minimises the sum of squared one-step prediction errors via the Levenberg–Marquardt algorithm and returns the estimated parameter values along with their standard deviations.
|
|
67
|
+
|
|
68
|
+
**4. Validate the model.** Check whether the fitted model is adequate. `uniChi` and `multiChi` perform portmanteau chi-square tests on the residuals and on the cross-correlation between residuals and inputs. `pmoddisp` shows parameter confidence intervals. `pmodpzplot` plots the pole-zero map. If the model fails validation, return to step 2 and adjust the order — or return to step 1 and try a different model class.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## The Prediction Model Framework
|
|
73
|
+
|
|
74
|
+
All models in this toolbox share a common structure: a linear filter driven by a white noise input $e(t)$ and, optionally, an observed external input $u(t)$. Every model can be written
|
|
75
|
+
|
|
76
|
+
$$y(t) = G(q)u(t) + H(q)e(t)$$
|
|
77
|
+
|
|
78
|
+
where $G(q)$ is the transfer function from input to output and $H(q)$ is the noise model. The models differ in how $G$ and $H$ are parameterized.
|
|
79
|
+
|
|
80
|
+
### The Backward Shift Operator
|
|
81
|
+
|
|
82
|
+
All models are expressed using the **backward shift operator** $q^{-1}$, defined by
|
|
83
|
+
|
|
84
|
+
$$q^{-k}y(t) = y(t-k)$$
|
|
85
|
+
|
|
86
|
+
A polynomial in $q^{-1}$ of order $n_p$ is written
|
|
87
|
+
|
|
88
|
+
$$P(q) = 1 + p_1 q^{-1} + p_2 q^{-2} + \cdots + p_{n_p} q^{-n_p}$$
|
|
89
|
+
|
|
90
|
+
so that $P(q)y(t) = y(t) + p_1 y(t-1) + \cdots + p_n y(t-n_p)$.
|
|
91
|
+
|
|
92
|
+
Throughout this document $e(t)$ denotes a **white noise** sequence with zero mean and variance $\sigma^2$.
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
### Autoregressive (AR) Model
|
|
97
|
+
|
|
98
|
+
The simplest model expresses the current value of $y(t)$ as a weighted sum of its own past values plus white noise:
|
|
99
|
+
|
|
100
|
+
$$D(q)y(t) = e(t)$$
|
|
101
|
+
|
|
102
|
+
where the **autoregressive polynomial** is
|
|
103
|
+
|
|
104
|
+
$$D(q) = 1 + d_1 q^{-1} + \cdots + d_{n_d} q^{-n_d}$$
|
|
105
|
+
|
|
106
|
+
This is an AR($n_d$) model. The model is stationary when all roots of $D(z) = 0$ lie **outside** the unit circle. In the toolbox, a pure AR model is a special case of ARMA with $C(q) = 1$:
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
pmodel('arma', nc=[0], nd=[nd], diff=[0], per=[])
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
### Moving Average (MA) Model
|
|
115
|
+
|
|
116
|
+
A moving average model expresses $y(t)$ as a weighted sum of current and past noise values:
|
|
117
|
+
|
|
118
|
+
$$y(t) = C(q)e(t)$$
|
|
119
|
+
|
|
120
|
+
where the **moving average polynomial** is
|
|
121
|
+
|
|
122
|
+
$$C(q) = 1 + c_1 q^{-1} + \cdots + c_{n_c} q^{-n_c}$$
|
|
123
|
+
|
|
124
|
+
This is an MA($n_c$) model. The model is invertible when all roots of $C(z) = 0$ lie **outside** the unit circle. A pure MA model sets $D(q) = 1$:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
pmodel('arma', nc=[nc], nd=[0], diff=[0], per=[])
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
### Autoregressive Moving Average (ARMA) Model
|
|
133
|
+
|
|
134
|
+
Combining both components gives the ARMA($n_d$, $n_c$) model:
|
|
135
|
+
|
|
136
|
+
$$D(q)y(t) = C(q)e(t)$$
|
|
137
|
+
|
|
138
|
+
The noise is modeled by the transfer function $H(q) = C(q)/D(q)$. An ARMA model is typically more parsimonious than a pure AR or MA model of equivalent fit quality: a low-order ARMA can often replace a high-order AR.
|
|
139
|
+
|
|
140
|
+
```python
|
|
141
|
+
pmodel('arma', nc=[nc], nd=[nd], diff=[0], per=[])
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
### ARIMA Model
|
|
147
|
+
|
|
148
|
+
Many real-world series are **non-stationary** — their mean or variance drifts over time. The ARIMA($n_d$, $d$, $n_c$) model handles this by differencing the series $d$ times before fitting an ARMA model. The difference operator is
|
|
149
|
+
|
|
150
|
+
$$\nabla = 1 - q^{-1}, \qquad \nabla^d y(t) = (1 - q^{-1})^dy(t)$$
|
|
151
|
+
|
|
152
|
+
so that $\nabla y(t) = y(t) - y(t-1)$ and $\nabla^2 y(t) = y(t) - 2y(t-1) + y(t-2)$. The model equation is
|
|
153
|
+
|
|
154
|
+
$$D(q)\nabla^d y(t) = C(q)e(t)$$
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
pmodel('arma', nc=[nc], nd=[nd], diff=[d], per=[])
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
### Seasonal ARIMA Model
|
|
163
|
+
|
|
164
|
+
Seasonal data — such as hourly data with a daily cycle or monthly data with a yearly cycle — requires both a regular and a **seasonal** ARMA component. Let $s$ denote the period (e.g., $s = 24$ for hourly data with a daily pattern). The seasonal difference operator is $\nabla_s = 1 - q^{-s}$.
|
|
165
|
+
|
|
166
|
+
Seasonal AR and MA polynomials involve lags that are multiples of $s$, with orders $n_{d,s}$ and $n_{c,s}$ respectively:
|
|
167
|
+
|
|
168
|
+
$$D_s(q^{-s}) = 1 + d_{s,1}q^{-s} + \cdots + d_{s,n_{d,s}}q^{-n_{d,s} s}$$
|
|
169
|
+
|
|
170
|
+
$$C_s(q^{-s}) = 1 + c_{s,1}q^{-s} + \cdots + c_{s,n_{c,s}}q^{-n_{c,s} s}$$
|
|
171
|
+
|
|
172
|
+
The seasonal ARIMA model with non-seasonal differencing order $d$ and seasonal differencing order $d_s$ is
|
|
173
|
+
|
|
174
|
+
$$D(q)D_s(q^{-s})\nabla^d\nabla_s^{d_s}y(t) = C(q)C_s(q^{-s})e(t)$$
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
pmodel('arma', nc=[nc, nc_s], nd=[nd, nd_s], diff=[d, d_s], per=[s])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
### ARX Model — Equation Error Form
|
|
183
|
+
|
|
184
|
+
When an observed external input $u(t)$ is available, the simplest extension adds an input term and an autoregressive filter:
|
|
185
|
+
|
|
186
|
+
$$A(q)y(t) = B(q)q^{-k}u(t) + e(t)$$
|
|
187
|
+
|
|
188
|
+
where $k$ is the pure input delay and
|
|
189
|
+
|
|
190
|
+
$$A(q) = 1 + a_1 q^{-1} + \cdots + a_{n_a} q^{-n_a}$$
|
|
191
|
+
|
|
192
|
+
$$B(q) = b_0 + b_1 q^{-1} + \cdots + b_{n_b} q^{-n_b}$$
|
|
193
|
+
|
|
194
|
+
The transfer functions are
|
|
195
|
+
|
|
196
|
+
$$G(q) = \frac{B(q)}{A(q)}q^{-k}, \qquad H(q) = \frac{1}{A(q)}$$
|
|
197
|
+
|
|
198
|
+
Note that the **same polynomial** $A(q)$ governs both the input dynamics and the noise model. Because the noise $e(t)$ appears as an additive "equation error," the parameters can be estimated by linear least squares — a significant computational advantage. The trade-off is that the noise poles are constrained to equal the input poles.
|
|
199
|
+
|
|
200
|
+
```python
|
|
201
|
+
pmodel('arx', na=na, nb=[nb], delay=[k])
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
### ARMAX Model — Equation Error Form
|
|
207
|
+
|
|
208
|
+
Adding a moving average term to the noise model relaxes the noise-pole constraint:
|
|
209
|
+
|
|
210
|
+
$$A(q)y(t) = B(q)q^{-k}u(t) + C(q)e(t)$$
|
|
211
|
+
|
|
212
|
+
The transfer functions are
|
|
213
|
+
|
|
214
|
+
$$G(q) = \frac{B(q)}{A(q)}q^{-k}, \qquad H(q) = \frac{C(q)}{A(q)}$$
|
|
215
|
+
|
|
216
|
+
The polynomial $A(q)$ still appears in both $G$ and $H$, so the noise poles remain tied to the input poles. The extra $C(q)$ numerator provides more flexibility in shaping the noise spectrum without adding new poles. Parameter estimation requires non-linear optimization; the toolbox uses the Levenberg–Marquardt algorithm.
|
|
217
|
+
|
|
218
|
+
```python
|
|
219
|
+
pmodel('armax', na=na, nb=[nb], nc=nc, delay=[k])
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### Box-Jenkins Transfer Function (BJTF) Model — Output Error Form
|
|
225
|
+
|
|
226
|
+
The most general model in the toolbox gives the input dynamics and the noise model **completely independent** parameterizations:
|
|
227
|
+
|
|
228
|
+
$$y(t) = \frac{B(q)}{F(q)}q^{-k}u(t) + \frac{C(q)}{D(q)}e(t)$$
|
|
229
|
+
|
|
230
|
+
where
|
|
231
|
+
|
|
232
|
+
$$F(q) = 1 + f_1 q^{-1} + \cdots + f_{n_f} q^{-n_f}$$
|
|
233
|
+
|
|
234
|
+
The four polynomials $B$, $F$, $C$, $D$ can be chosen independently. This separation means the noise model can be identified without contamination from the input dynamics — the defining property of the "output error" form.
|
|
235
|
+
|
|
236
|
+
The noise transfer function $H(q) = C(q)/D(q)$ reduces to $1/D(q)$ when $C(q) = 1$, giving a special case with a purely autoregressive noise model. Setting $F(q) = A(q)$ and $D(q) = A(q)$ recovers ARMAX; additionally setting $C(q) = 1$ recovers ARX.
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
pmodel('bjtf', nb=[nb], nc=[nc], nd=[nd], nf=[nf], delay=[k])
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
### One-Step-Ahead Predictor
|
|
245
|
+
|
|
246
|
+
All models share a common predictor structure. Given the noise transfer function $H(q) = C(q)/D(q)$, the optimal one-step-ahead predictor is
|
|
247
|
+
|
|
248
|
+
$$\hat{y}(t \mid t-1) = \left[1 - H^{-1}(q)\right]y(t) + H^{-1}(q)G(q)u(t)$$
|
|
249
|
+
|
|
250
|
+
For the BJTF model this expands to
|
|
251
|
+
|
|
252
|
+
$$\hat{y}(t) = \frac{C(q) - D(q)}{C(q)}y(t) + \frac{D(q)B(q)q^{-k}}{C(q)F(q)}u(t)$$
|
|
253
|
+
|
|
254
|
+
The toolbox minimizes the sum of squared one-step prediction errors $\sum_t [y(t) - \hat{y}(t)]^2$ using the **Levenberg–Marquardt** algorithm.
|
|
255
|
+
|
|
256
|
+
---
|
|
257
|
+
|
|
258
|
+
### Model Summary
|
|
259
|
+
|
|
260
|
+
| Model | AR poly. | Input $B$ | MA poly. $C$ | Input den. $F$ | Notes |
|
|
261
|
+
|-------|----------|-----------|--------------|----------------|-------|
|
|
262
|
+
| AR | $D$ | — | — | — | $C=1$ |
|
|
263
|
+
| MA | — | — | $C$ | — | $D=1$ |
|
|
264
|
+
| ARMA | $D$ | — | $C$ | — | noise only |
|
|
265
|
+
| ARIMA | $D$ | — | $C$ | — | + differencing $\nabla^d$ |
|
|
266
|
+
| Seasonal ARIMA | $D,D_s$ | — | $C,C_s$ | — | + seasonal $\nabla_s^{d_s}$ |
|
|
267
|
+
| ARX | $A$ | $B$ | — | $A$ (shared) | equation error |
|
|
268
|
+
| ARMAX | $A$ | $B$ | $C$ | $A$ (shared) | equation error |
|
|
269
|
+
| BJTF | $D$ | $B$ | $C$ | $F$ | output error |
|
|
270
|
+
|
|
271
|
+
---
|
|
272
|
+
|
|
273
|
+
## Toolbox
|
|
274
|
+
|
|
275
|
+
📖 **[User Guide](https://amir-jafari.github.io/TimeSeries/UserGuide.html)** — complete function reference with calling formats and argument descriptions.
|
|
276
|
+
|
|
277
|
+
### Installation
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
pip install timeseries-toolbox
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Requirements:** Python ≥ 3.8 · NumPy ≥ 1.19 · SciPy ≥ 1.5 · Matplotlib ≥ 3.3
|
|
284
|
+
|
|
285
|
+
---
|
|
286
|
+
|
|
287
|
+
### Quick Start
|
|
288
|
+
|
|
289
|
+
```python
|
|
290
|
+
import numpy as np
|
|
291
|
+
from TimeSeriesSRC.Model.model import pmodel
|
|
292
|
+
from TimeSeriesSRC.Model.estimate import estimate
|
|
293
|
+
from TimeSeriesSRC.basefunctions.uniAnal import func_uniAnal as uniAnal
|
|
294
|
+
from TimeSeriesSRC.basefunctions.multiAnal import func_multiAnal as multiAnal
|
|
295
|
+
from TimeSeriesSRC.Model.selpmod import func_selpmod as selpmod
|
|
296
|
+
from TimeSeriesSRC.Model.pmoddisp import func_pmoddisp as pmoddisp
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Univariate analysis** — ACF, PACF, GPAC
|
|
300
|
+
```python
|
|
301
|
+
acf, pacf, gpac = uniAnal(y, na=20, nump=10)
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Fit and estimate an ARMA model**
|
|
305
|
+
```python
|
|
306
|
+
pmod = pmodel('arma', nc=[3], nd=[2], diff=[0], per=[])
|
|
307
|
+
pmod, trec, stat = estimate(pmod, y)
|
|
308
|
+
yhat = pmod.predict(y)
|
|
309
|
+
pmoddisp(pmod, stat) # parameter table + confidence intervals
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Fit a BJTF model**
|
|
313
|
+
```python
|
|
314
|
+
pmod = pmodel('bjtf', nb=[2], nc=[0], nd=[2], nf=[2], delay=[3], diff=[0], per=[])
|
|
315
|
+
pmod, trec, stat = estimate(pmod, y, u)
|
|
316
|
+
yhat = pmod.predict(y, u)
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**Automatic model selection by AIC / BIC**
|
|
320
|
+
```python
|
|
321
|
+
spec = {
|
|
322
|
+
'models': [{'type': 'arma', 'nc': [0, 1, 2], 'nd': [1, 2, 3], 'diff': [0]}]
|
|
323
|
+
}
|
|
324
|
+
result = selpmod(spec, y)
|
|
325
|
+
best = result['arma']['bicmod']
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
---
|
|
329
|
+
|
|
330
|
+
### Package Structure
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
TimeSeriesSRC/
|
|
334
|
+
├── basefunctions/ # uniAnal, multiAnal, gpac, xcorr, partoacf, uniChi, multiChi, …
|
|
335
|
+
├── Model/ # pmodel, estimate, selpmod, pmodaic, pmodbic, pmoddisp, …
|
|
336
|
+
├── Examples/
|
|
337
|
+
│ ├── NoteBooks/ # Jupyter notebook walkthroughs
|
|
338
|
+
│ └── PyFiles/ # Python script versions
|
|
339
|
+
└── TestData/ # Gas furnace and other benchmark datasets
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
### Example Notebooks
|
|
345
|
+
|
|
346
|
+
End-to-end walkthroughs of the four-step system identification process, each on a different Box-Jenkins benchmark dataset.
|
|
347
|
+
|
|
348
|
+
| Notebook | Model class | Dataset |
|
|
349
|
+
|----------|-------------|---------|
|
|
350
|
+
| [01 — ARMA Model](TimeSeriesSRC/Examples/NoteBooks/01_ARMA_Model.ipynb) | ARMA | Series A — Chemical Concentration (197 obs.) |
|
|
351
|
+
| [02 — ARIMA Model](TimeSeriesSRC/Examples/NoteBooks/02_ARIMA_Model.ipynb) | ARIMA | Series C — Chemical Temperature (226 obs.) |
|
|
352
|
+
| [03 — Seasonal ARIMA Model](TimeSeriesSRC/Examples/NoteBooks/03_Seasonal_ARIMA_Model.ipynb) | Seasonal ARIMA | Series G — Airline Passengers (144 obs.) |
|
|
353
|
+
| [04 — BJTF / ARMAX / ARX Model](TimeSeriesSRC/Examples/NoteBooks/04_BJTF_Model.ipynb) | BJTF, ARMAX, ARX | Series J — Gas Furnace (296 obs.) |
|
|
354
|
+
|
|
355
|
+
Python script equivalents are in [TimeSeriesSRC/Examples/PyFiles/](TimeSeriesSRC/Examples/PyFiles/).
|
|
356
|
+
|
|
357
|
+
---
|
|
358
|
+
|
|
359
|
+
### Key Functions
|
|
360
|
+
|
|
361
|
+
#### Analysis
|
|
362
|
+
|
|
363
|
+
| Function | Description |
|
|
364
|
+
|----------|-------------|
|
|
365
|
+
| `uniAnal(y, na, nump)` | ACF, PACF and GPAC for a single series |
|
|
366
|
+
| `multiAnal(u, y, ...)` | Impulse response, residual ACF and GPAC for $u \to y$ |
|
|
367
|
+
| `uniChi(pmod, y)` | Chi-square test on model residuals |
|
|
368
|
+
| `multiChi(pmod, y, u)` | Chi-square test for transfer function residuals |
|
|
369
|
+
| `partoacf_pmod(pmod, var_e, lagmax)` | Theoretical ACF from a fitted model |
|
|
370
|
+
|
|
371
|
+
#### Model Selection
|
|
372
|
+
|
|
373
|
+
| Function | Description |
|
|
374
|
+
|----------|-------------|
|
|
375
|
+
| `selpmod(spec, y, u)` | Grid search over model structures; returns best AIC and BIC models |
|
|
376
|
+
| `pmodaic(pmod, y, u)` | Akaike Information Criterion |
|
|
377
|
+
| `pmodbic(pmod, y, u)` | Bayesian Information Criterion |
|
|
378
|
+
| `pmodmse(pmod, y, u)` | Mean squared prediction error |
|
|
379
|
+
|
|
380
|
+
#### Display and Diagnostics
|
|
381
|
+
|
|
382
|
+
| Function | Description |
|
|
383
|
+
|----------|-------------|
|
|
384
|
+
| `pmoddisp(pmod, stat)` | Parameter table with ±2σ confidence intervals and error-bar plot |
|
|
385
|
+
| `pmodpzplot(pmod)` | Pole-zero map for the $G$ and $H$ transfer functions |
|
|
386
|
+
|
|
387
|
+
---
|
|
388
|
+
|
|
389
|
+
## References
|
|
390
|
+
|
|
391
|
+
- G. E. P. Box and G. M. Jenkins, *Time Series Analysis: Forecasting and Control*, Holden-Day, 1970.
|
|
392
|
+
- L. Ljung, *System Identification: Theory for the User*, Prentice Hall, 1987.
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Authors
|
|
397
|
+
|
|
398
|
+
Martin Hagan · Amir Jafari · Lilian S. De Rivera
|
|
399
|
+
|
|
400
|
+
## License
|
|
401
|
+
|
|
402
|
+
MIT
|