tempdisagg 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.
- tempdisagg-0.1.0/LICENSE +21 -0
- tempdisagg-0.1.0/PKG-INFO +243 -0
- tempdisagg-0.1.0/README.md +220 -0
- tempdisagg-0.1.0/pyproject.toml +43 -0
- tempdisagg-0.1.0/setup.cfg +4 -0
- tempdisagg-0.1.0/tempdisagg/__init__.py +3 -0
- tempdisagg-0.1.0/tempdisagg/core/__init__.py +9 -0
- tempdisagg-0.1.0/tempdisagg/core/numeric_utils.py +151 -0
- tempdisagg-0.1.0/tempdisagg/core/rho_optimizer.py +212 -0
- tempdisagg-0.1.0/tempdisagg/core/temporal_aggregator.py +82 -0
- tempdisagg-0.1.0/tempdisagg/model/__init__.py +7 -0
- tempdisagg-0.1.0/tempdisagg/model/models_handler.py +515 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_adjuster.py +15 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_core.py +165 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_ensemble.py +40 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_model.py +23 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_summary.py +116 -0
- tempdisagg-0.1.0/tempdisagg/model/tempdisagg_visualizer.py +36 -0
- tempdisagg-0.1.0/tempdisagg/postprocessing/__init__.py +7 -0
- tempdisagg-0.1.0/tempdisagg/postprocessing/ensemble_prediction.py +298 -0
- tempdisagg-0.1.0/tempdisagg/postprocessing/post_estimation.py +245 -0
- tempdisagg-0.1.0/tempdisagg/preprocessing/__init__.py +11 -0
- tempdisagg-0.1.0/tempdisagg/preprocessing/conversion_matrix_builder.py +150 -0
- tempdisagg-0.1.0/tempdisagg/preprocessing/disagg_input_preparer.py +142 -0
- tempdisagg-0.1.0/tempdisagg/preprocessing/input_preprocessor.py +115 -0
- tempdisagg-0.1.0/tempdisagg/preprocessing/timeseries_completer.py +238 -0
- tempdisagg-0.1.0/tempdisagg/utils/__init__.py +6 -0
- tempdisagg-0.1.0/tempdisagg/utils/logging_utils.py +68 -0
- tempdisagg-0.1.0/tempdisagg.egg-info/PKG-INFO +243 -0
- tempdisagg-0.1.0/tempdisagg.egg-info/SOURCES.txt +59 -0
- tempdisagg-0.1.0/tempdisagg.egg-info/dependency_links.txt +1 -0
- tempdisagg-0.1.0/tempdisagg.egg-info/requires.txt +4 -0
- tempdisagg-0.1.0/tempdisagg.egg-info/top_level.txt +1 -0
- tempdisagg-0.1.0/tests/test_adjuster.py +8 -0
- tempdisagg-0.1.0/tests/test_ensemble.py +10 -0
- tempdisagg-0.1.0/tests/test_model_core.py +8 -0
- tempdisagg-0.1.0/tests/test_numeric_utils.py +7 -0
- tempdisagg-0.1.0/tests/test_rho_optimizer.py +12 -0
tempdisagg-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Jaime Vera-Jaramillo
|
|
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
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: tempdisagg
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Temporal disaggregation models in Python
|
|
5
|
+
Author-email: Jaime Vera-Jaramillo <jaimevera1107@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/tu_usuario/tempdisagg
|
|
8
|
+
Keywords: temporal disaggregation,time series,econometrics,interpolation
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Science/Research
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Operating System :: OS Independent
|
|
15
|
+
Requires-Python: >=3.8
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE
|
|
18
|
+
Requires-Dist: numpy>=1.21
|
|
19
|
+
Requires-Dist: pandas>=1.3
|
|
20
|
+
Requires-Dist: scipy>=1.7
|
|
21
|
+
Requires-Dist: matplotlib>=3.4
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
|
|
24
|
+
# ⚡️ tempdisagg
|
|
25
|
+
|
|
26
|
+
> **Temporal Disaggregation Models in Python — Modular · Robust · Ready for Production**
|
|
27
|
+
|
|
28
|
+

|
|
29
|
+

|
|
30
|
+

|
|
31
|
+

|
|
32
|
+

|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
`tempdisagg` is a Python library for **temporal disaggregation of time series data**.
|
|
37
|
+
It supports all classical methods — **Chow-Lin**, **Litterman**, **Denton**, **Fernández**, **Uniform** — and offers a **modular, extensible, production-grade** architecture, inspired by the R package `tempdisagg`.
|
|
38
|
+
|
|
39
|
+
✨ The library combines:
|
|
40
|
+
- 📈 Regression-based models
|
|
41
|
+
- 📉 Differencing & smoothing techniques
|
|
42
|
+
- 🤖 Ensemble learning
|
|
43
|
+
- 🛠 Post-estimation adjustments
|
|
44
|
+
- 🧠 Full integration with the Python scientific stack
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
Many official statistics and business indicators are reported at low frequencies (e.g., annually or quarterly), but decision-making often demands **high-frequency estimates**.
|
|
49
|
+
Temporal disaggregation bridges this gap by producing granular series that **preserve consistency with aggregate values**.
|
|
50
|
+
|
|
51
|
+
**`tempdisagg`** provides a flexible interface to solve this problem — using econometric, statistical and machine learning techniques in a unified Pythonic API.
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
## 📚 Methods Implemented
|
|
57
|
+
|
|
58
|
+
| Method(s) | Description |
|
|
59
|
+
|---------------------------------------------------------------------------|---------------------------------------------------------------|
|
|
60
|
+
| `ols` | Ordinary Least Squares (baseline) |
|
|
61
|
+
| `denton`, `denton-opt` | Denton interpolation with optional differencing |
|
|
62
|
+
| `denton-cholette` | Modified smoother from Dagum & Cholette |
|
|
63
|
+
| `chow-lin`, `chow-lin-opt`, `chow-lin-ecotrim`, `chow-lin-quilis` | Regression-based disaggregation with autoregressive adjustment |
|
|
64
|
+
| `litterman`, `litterman-opt` | Litterman method with random walk / AR(1) prior |
|
|
65
|
+
| `fernandez` | Second-order differencing (Litterman with ρ = 0) |
|
|
66
|
+
| `fast` | Fast approximation of `denton-cholette` |
|
|
67
|
+
| `uniform` | Uniform distribution across subperiods |
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## 🛠️ Installation
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
pip install tempdisagg
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 💡 Quick Example
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
from tempdisagg import TempDisaggModel
|
|
81
|
+
|
|
82
|
+
# Create your DataFrame
|
|
83
|
+
df = pd.DataFrame({
|
|
84
|
+
"Index": [2020]*12 + [2021]*12,
|
|
85
|
+
"Grain": list(range(1, 13))*2,
|
|
86
|
+
"y": [1200] + [np.nan]*11 + [1500] + [np.nan]*11,
|
|
87
|
+
"X": np.linspace(100, 200, 24)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
# Initialize and fit model
|
|
91
|
+
model = TempDisaggModel(method="chow-lin-opt", conversion="sum")
|
|
92
|
+
model.fit(df)
|
|
93
|
+
|
|
94
|
+
# Predict high-frequency series
|
|
95
|
+
y_hat = model.predict()
|
|
96
|
+
|
|
97
|
+
# Summary and plots
|
|
98
|
+
model.summary()
|
|
99
|
+
model.plot(df)
|
|
100
|
+
```
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### 🤖 How does the Ensemble Prediction work?
|
|
104
|
+
|
|
105
|
+
The ensemble module allows combining multiple disaggregation methods into a single high-frequency estimate. It works by:
|
|
106
|
+
|
|
107
|
+
1. **Fitting multiple models** individually on the same input dataset using methods like `chow-lin`, `denton`, `fernandez`, etc.
|
|
108
|
+
2. **Computing the aggregated prediction error** (e.g., RMSE or MAE) of each model with respect to the low-frequency constraint.
|
|
109
|
+
3. **Optimizing weights** across models using non-negative least squares to minimize the error of the aggregated prediction (subject to weights summing to 1).
|
|
110
|
+
4. **Generating a final ensemble prediction**:
|
|
111
|
+
$$\hat{y}_{ensemble} = \sum_{i} w_i \cdot \hat{y}_i$$
|
|
112
|
+
where $\hat{y}_i$ is the prediction of the \(i\)-th model and \( w_i \) is its optimal weight.
|
|
113
|
+
|
|
114
|
+
Additional features:
|
|
115
|
+
- Bootstrap-based confidence intervals for the ensemble.
|
|
116
|
+
- Aggregated statistics such as average coefficients and combined R².
|
|
117
|
+
- Visual comparison of all component models via `.plot(df, show_individuals=True)`.
|
|
118
|
+
|
|
119
|
+
### 🤝 Ensemble Modeling
|
|
120
|
+
```python
|
|
121
|
+
model = temporal-dissagregationModel(conversion="average")
|
|
122
|
+
model.ensemble(df)
|
|
123
|
+
|
|
124
|
+
model.summary()
|
|
125
|
+
model.plot(df, use_adjusted=True)
|
|
126
|
+
```
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### 🚫 How does the Negative Value Adjustment work?
|
|
131
|
+
|
|
132
|
+
Temporal disaggregation methods may produce negative high-frequency values when:
|
|
133
|
+
- The low-frequency total is small.
|
|
134
|
+
- The method uses strong differencing or extrapolation.
|
|
135
|
+
- Indicator series are noisy or weakly correlated.
|
|
136
|
+
|
|
137
|
+
To address this, `tempdisagg` applies a post-estimation adjustment that:
|
|
138
|
+
|
|
139
|
+
1. **Detects negative predictions** in `y_hat`.
|
|
140
|
+
2. **Groups values** by low-frequency periods using the conversion matrix \( C \).
|
|
141
|
+
3. **Redistributes residuals** within each group to ensure all values are non-negative and consistent:
|
|
142
|
+
- Preserves the original sum (`C @ y_hat_adjusted = y_l`).
|
|
143
|
+
- Applies proportional or uniform redistribution to correct negatives.
|
|
144
|
+
- Ensures $\hat{y}_{adjusted} \geq 0 $ without breaking constraints.
|
|
145
|
+
|
|
146
|
+
### ✅ Negatives Adjustment
|
|
147
|
+
```python
|
|
148
|
+
model = temporal-dissagregationModel(conversion="average")
|
|
149
|
+
model.predict(df)
|
|
150
|
+
model.adjust_output(df)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
## 🗂️ Input Time Series Format
|
|
158
|
+
|
|
159
|
+
To use `TempDisModel`, your time series data must be organized in a **long-format DataFrame** with one row per high-frequency observation. The model requires the following columns:
|
|
160
|
+
|
|
161
|
+
| Column | Description |
|
|
162
|
+
|-----------------|-------------|
|
|
163
|
+
| `Index` | Identifier for the low-frequency group (e.g., year, quarter). This groups the target values. |
|
|
164
|
+
| `Grain` | Identifier for the high-frequency breakdown within each `Index` (e.g., month, quarter number). |
|
|
165
|
+
| `y` | The **low-frequency target variable** (repeated across the group). This is the variable to disaggregate. |
|
|
166
|
+
| `X` | The **high-frequency indicator** variable (available at the granular level). Used to guide the disaggregation. |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
#### 🔢 Example Structure
|
|
171
|
+
|
|
172
|
+
| Index | Grain | y | X |
|
|
173
|
+
|-------|-------|---------|-----------|
|
|
174
|
+
| 2000 | 1 | 1000.00 | 80.21 |
|
|
175
|
+
| 2000 | 2 | 1000.00 | 91.13 |
|
|
176
|
+
| 2000 | 3 | 1000.00 | 85.44 |
|
|
177
|
+
| 2000 | 4 | 1000.00 | 92.32 |
|
|
178
|
+
| 2001 | 1 | 1200.00 | 88.71 |
|
|
179
|
+
| 2001 | 2 | 1200.00 | 93.55 |
|
|
180
|
+
| ... | ... | ... | ... |
|
|
181
|
+
|
|
182
|
+
---
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
### ⚙️ API Overview
|
|
187
|
+
|
|
188
|
+
| Method | Description |
|
|
189
|
+
|-------------------------------|--------------------------------------------------------------|
|
|
190
|
+
| `.fit(df)` | Fit model to input DataFrame |
|
|
191
|
+
| `.predict()` | Return high-frequency `y_hat` |
|
|
192
|
+
| `.fit_predict(df)` | Shortcut to `.fit().predict()` |
|
|
193
|
+
| `.summary(metric="mae")` | Print summary with t-stats, AIC, BIC, R² |
|
|
194
|
+
| `.plot(df, use_adjusted=False)` | Plot predictions |
|
|
195
|
+
| `.adjust_output(df)` | Apply non-negative adjustment |
|
|
196
|
+
| `.ensemble(df, methods=...)` | Fit ensemble and combine multiple models |
|
|
197
|
+
| `.validate_aggregation()` | Check if `C @ y_hat ≈ y_l` |
|
|
198
|
+
| `.get_params()` / `.set_params()` | Get/set model configuration |
|
|
199
|
+
| `.to_dict()` | Export results in serializable dictionary |
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
## 🧠 Modular Architecture
|
|
204
|
+
|
|
205
|
+
The codebase follows a clean architecture with decoupled components:
|
|
206
|
+
|
|
207
|
+
- `TempDisaggModel`: High-level API
|
|
208
|
+
- `ModelsHandler`: Implements individual disaggregation methods
|
|
209
|
+
- `RhoOptimizer`: Optimizes autocorrelation
|
|
210
|
+
- `DisaggInputPreparer`: Manages time series preparation
|
|
211
|
+
- `PostEstimation`: Adjusts predictions post-estimation
|
|
212
|
+
- `EnsemblePrediction`: Combines multiple models into one
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
### 🧪 Testing & Validation
|
|
216
|
+
|
|
217
|
+
The library includes:
|
|
218
|
+
|
|
219
|
+
- Unit tests for all modules
|
|
220
|
+
- Validation of input dimensions and types
|
|
221
|
+
- Aggregation consistency checks
|
|
222
|
+
- Support for NaNs and ragged time indices
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
## 🧩 **Related Projects**
|
|
226
|
+
|
|
227
|
+
**In R:**
|
|
228
|
+
- [`tempdisagg`](https://cran.r-project.org/package=tempdisagg) – Reference package for temporal disaggregation.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 📚 **References and Acknowledgements**
|
|
233
|
+
|
|
234
|
+
This library draws inspiration from the R ecosystem and academic literature on temporal disaggregation.
|
|
235
|
+
|
|
236
|
+
Their research laid the foundation for many techniques implemented here.
|
|
237
|
+
For a deeper review, we encourage exploring the reference section in the [`tempdisagg`](https://cran.r-project.org/package=tempdisagg) R package.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 📃 **License**
|
|
242
|
+
This project is licensed under the MIT License.
|
|
243
|
+
See the [LICENSE](./LICENSE) file for more details.
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
# ⚡️ tempdisagg
|
|
2
|
+
|
|
3
|
+
> **Temporal Disaggregation Models in Python — Modular · Robust · Ready for Production**
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
8
|
+

|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
`tempdisagg` is a Python library for **temporal disaggregation of time series data**.
|
|
14
|
+
It supports all classical methods — **Chow-Lin**, **Litterman**, **Denton**, **Fernández**, **Uniform** — and offers a **modular, extensible, production-grade** architecture, inspired by the R package `tempdisagg`.
|
|
15
|
+
|
|
16
|
+
✨ The library combines:
|
|
17
|
+
- 📈 Regression-based models
|
|
18
|
+
- 📉 Differencing & smoothing techniques
|
|
19
|
+
- 🤖 Ensemble learning
|
|
20
|
+
- 🛠 Post-estimation adjustments
|
|
21
|
+
- 🧠 Full integration with the Python scientific stack
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
Many official statistics and business indicators are reported at low frequencies (e.g., annually or quarterly), but decision-making often demands **high-frequency estimates**.
|
|
26
|
+
Temporal disaggregation bridges this gap by producing granular series that **preserve consistency with aggregate values**.
|
|
27
|
+
|
|
28
|
+
**`tempdisagg`** provides a flexible interface to solve this problem — using econometric, statistical and machine learning techniques in a unified Pythonic API.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
## 📚 Methods Implemented
|
|
34
|
+
|
|
35
|
+
| Method(s) | Description |
|
|
36
|
+
|---------------------------------------------------------------------------|---------------------------------------------------------------|
|
|
37
|
+
| `ols` | Ordinary Least Squares (baseline) |
|
|
38
|
+
| `denton`, `denton-opt` | Denton interpolation with optional differencing |
|
|
39
|
+
| `denton-cholette` | Modified smoother from Dagum & Cholette |
|
|
40
|
+
| `chow-lin`, `chow-lin-opt`, `chow-lin-ecotrim`, `chow-lin-quilis` | Regression-based disaggregation with autoregressive adjustment |
|
|
41
|
+
| `litterman`, `litterman-opt` | Litterman method with random walk / AR(1) prior |
|
|
42
|
+
| `fernandez` | Second-order differencing (Litterman with ρ = 0) |
|
|
43
|
+
| `fast` | Fast approximation of `denton-cholette` |
|
|
44
|
+
| `uniform` | Uniform distribution across subperiods |
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🛠️ Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install tempdisagg
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### 💡 Quick Example
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from tempdisagg import TempDisaggModel
|
|
58
|
+
|
|
59
|
+
# Create your DataFrame
|
|
60
|
+
df = pd.DataFrame({
|
|
61
|
+
"Index": [2020]*12 + [2021]*12,
|
|
62
|
+
"Grain": list(range(1, 13))*2,
|
|
63
|
+
"y": [1200] + [np.nan]*11 + [1500] + [np.nan]*11,
|
|
64
|
+
"X": np.linspace(100, 200, 24)
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
# Initialize and fit model
|
|
68
|
+
model = TempDisaggModel(method="chow-lin-opt", conversion="sum")
|
|
69
|
+
model.fit(df)
|
|
70
|
+
|
|
71
|
+
# Predict high-frequency series
|
|
72
|
+
y_hat = model.predict()
|
|
73
|
+
|
|
74
|
+
# Summary and plots
|
|
75
|
+
model.summary()
|
|
76
|
+
model.plot(df)
|
|
77
|
+
```
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
### 🤖 How does the Ensemble Prediction work?
|
|
81
|
+
|
|
82
|
+
The ensemble module allows combining multiple disaggregation methods into a single high-frequency estimate. It works by:
|
|
83
|
+
|
|
84
|
+
1. **Fitting multiple models** individually on the same input dataset using methods like `chow-lin`, `denton`, `fernandez`, etc.
|
|
85
|
+
2. **Computing the aggregated prediction error** (e.g., RMSE or MAE) of each model with respect to the low-frequency constraint.
|
|
86
|
+
3. **Optimizing weights** across models using non-negative least squares to minimize the error of the aggregated prediction (subject to weights summing to 1).
|
|
87
|
+
4. **Generating a final ensemble prediction**:
|
|
88
|
+
$$\hat{y}_{ensemble} = \sum_{i} w_i \cdot \hat{y}_i$$
|
|
89
|
+
where $\hat{y}_i$ is the prediction of the \(i\)-th model and \( w_i \) is its optimal weight.
|
|
90
|
+
|
|
91
|
+
Additional features:
|
|
92
|
+
- Bootstrap-based confidence intervals for the ensemble.
|
|
93
|
+
- Aggregated statistics such as average coefficients and combined R².
|
|
94
|
+
- Visual comparison of all component models via `.plot(df, show_individuals=True)`.
|
|
95
|
+
|
|
96
|
+
### 🤝 Ensemble Modeling
|
|
97
|
+
```python
|
|
98
|
+
model = temporal-dissagregationModel(conversion="average")
|
|
99
|
+
model.ensemble(df)
|
|
100
|
+
|
|
101
|
+
model.summary()
|
|
102
|
+
model.plot(df, use_adjusted=True)
|
|
103
|
+
```
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
### 🚫 How does the Negative Value Adjustment work?
|
|
108
|
+
|
|
109
|
+
Temporal disaggregation methods may produce negative high-frequency values when:
|
|
110
|
+
- The low-frequency total is small.
|
|
111
|
+
- The method uses strong differencing or extrapolation.
|
|
112
|
+
- Indicator series are noisy or weakly correlated.
|
|
113
|
+
|
|
114
|
+
To address this, `tempdisagg` applies a post-estimation adjustment that:
|
|
115
|
+
|
|
116
|
+
1. **Detects negative predictions** in `y_hat`.
|
|
117
|
+
2. **Groups values** by low-frequency periods using the conversion matrix \( C \).
|
|
118
|
+
3. **Redistributes residuals** within each group to ensure all values are non-negative and consistent:
|
|
119
|
+
- Preserves the original sum (`C @ y_hat_adjusted = y_l`).
|
|
120
|
+
- Applies proportional or uniform redistribution to correct negatives.
|
|
121
|
+
- Ensures $\hat{y}_{adjusted} \geq 0 $ without breaking constraints.
|
|
122
|
+
|
|
123
|
+
### ✅ Negatives Adjustment
|
|
124
|
+
```python
|
|
125
|
+
model = temporal-dissagregationModel(conversion="average")
|
|
126
|
+
model.predict(df)
|
|
127
|
+
model.adjust_output(df)
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
## 🗂️ Input Time Series Format
|
|
135
|
+
|
|
136
|
+
To use `TempDisModel`, your time series data must be organized in a **long-format DataFrame** with one row per high-frequency observation. The model requires the following columns:
|
|
137
|
+
|
|
138
|
+
| Column | Description |
|
|
139
|
+
|-----------------|-------------|
|
|
140
|
+
| `Index` | Identifier for the low-frequency group (e.g., year, quarter). This groups the target values. |
|
|
141
|
+
| `Grain` | Identifier for the high-frequency breakdown within each `Index` (e.g., month, quarter number). |
|
|
142
|
+
| `y` | The **low-frequency target variable** (repeated across the group). This is the variable to disaggregate. |
|
|
143
|
+
| `X` | The **high-frequency indicator** variable (available at the granular level). Used to guide the disaggregation. |
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
#### 🔢 Example Structure
|
|
148
|
+
|
|
149
|
+
| Index | Grain | y | X |
|
|
150
|
+
|-------|-------|---------|-----------|
|
|
151
|
+
| 2000 | 1 | 1000.00 | 80.21 |
|
|
152
|
+
| 2000 | 2 | 1000.00 | 91.13 |
|
|
153
|
+
| 2000 | 3 | 1000.00 | 85.44 |
|
|
154
|
+
| 2000 | 4 | 1000.00 | 92.32 |
|
|
155
|
+
| 2001 | 1 | 1200.00 | 88.71 |
|
|
156
|
+
| 2001 | 2 | 1200.00 | 93.55 |
|
|
157
|
+
| ... | ... | ... | ... |
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
### ⚙️ API Overview
|
|
164
|
+
|
|
165
|
+
| Method | Description |
|
|
166
|
+
|-------------------------------|--------------------------------------------------------------|
|
|
167
|
+
| `.fit(df)` | Fit model to input DataFrame |
|
|
168
|
+
| `.predict()` | Return high-frequency `y_hat` |
|
|
169
|
+
| `.fit_predict(df)` | Shortcut to `.fit().predict()` |
|
|
170
|
+
| `.summary(metric="mae")` | Print summary with t-stats, AIC, BIC, R² |
|
|
171
|
+
| `.plot(df, use_adjusted=False)` | Plot predictions |
|
|
172
|
+
| `.adjust_output(df)` | Apply non-negative adjustment |
|
|
173
|
+
| `.ensemble(df, methods=...)` | Fit ensemble and combine multiple models |
|
|
174
|
+
| `.validate_aggregation()` | Check if `C @ y_hat ≈ y_l` |
|
|
175
|
+
| `.get_params()` / `.set_params()` | Get/set model configuration |
|
|
176
|
+
| `.to_dict()` | Export results in serializable dictionary |
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
## 🧠 Modular Architecture
|
|
181
|
+
|
|
182
|
+
The codebase follows a clean architecture with decoupled components:
|
|
183
|
+
|
|
184
|
+
- `TempDisaggModel`: High-level API
|
|
185
|
+
- `ModelsHandler`: Implements individual disaggregation methods
|
|
186
|
+
- `RhoOptimizer`: Optimizes autocorrelation
|
|
187
|
+
- `DisaggInputPreparer`: Manages time series preparation
|
|
188
|
+
- `PostEstimation`: Adjusts predictions post-estimation
|
|
189
|
+
- `EnsemblePrediction`: Combines multiple models into one
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
### 🧪 Testing & Validation
|
|
193
|
+
|
|
194
|
+
The library includes:
|
|
195
|
+
|
|
196
|
+
- Unit tests for all modules
|
|
197
|
+
- Validation of input dimensions and types
|
|
198
|
+
- Aggregation consistency checks
|
|
199
|
+
- Support for NaNs and ragged time indices
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
## 🧩 **Related Projects**
|
|
203
|
+
|
|
204
|
+
**In R:**
|
|
205
|
+
- [`tempdisagg`](https://cran.r-project.org/package=tempdisagg) – Reference package for temporal disaggregation.
|
|
206
|
+
|
|
207
|
+
---
|
|
208
|
+
|
|
209
|
+
## 📚 **References and Acknowledgements**
|
|
210
|
+
|
|
211
|
+
This library draws inspiration from the R ecosystem and academic literature on temporal disaggregation.
|
|
212
|
+
|
|
213
|
+
Their research laid the foundation for many techniques implemented here.
|
|
214
|
+
For a deeper review, we encourage exploring the reference section in the [`tempdisagg`](https://cran.r-project.org/package=tempdisagg) R package.
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## 📃 **License**
|
|
219
|
+
This project is licensed under the MIT License.
|
|
220
|
+
See the [LICENSE](./LICENSE) file for more details.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tempdisagg"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Temporal disaggregation models in Python"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
authors = [
|
|
11
|
+
{ name = "Jaime Vera-Jaramillo", email = "jaimevera1107@gmail.com" }
|
|
12
|
+
]
|
|
13
|
+
license = { text = "MIT" }
|
|
14
|
+
keywords = ["temporal disaggregation", "time series", "econometrics", "interpolation"]
|
|
15
|
+
classifiers = [
|
|
16
|
+
"Development Status :: 4 - Beta",
|
|
17
|
+
"Intended Audience :: Science/Research",
|
|
18
|
+
"License :: OSI Approved :: MIT License",
|
|
19
|
+
"Programming Language :: Python :: 3",
|
|
20
|
+
"Programming Language :: Python :: 3.8",
|
|
21
|
+
"Operating System :: OS Independent"
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
requires-python = ">=3.8"
|
|
25
|
+
dependencies = [
|
|
26
|
+
"numpy>=1.21",
|
|
27
|
+
"pandas>=1.3",
|
|
28
|
+
"scipy>=1.7",
|
|
29
|
+
"matplotlib>=3.4"
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
[project.urls]
|
|
33
|
+
Homepage = "https://github.com/tu_usuario/tempdisagg"
|
|
34
|
+
|
|
35
|
+
[tool.setuptools.packages.find]
|
|
36
|
+
where = ["."]
|
|
37
|
+
include = ["tempdisagg*"]
|
|
38
|
+
|
|
39
|
+
[tool.setuptools.package-data]
|
|
40
|
+
tempdisagg = ["py.typed"]
|
|
41
|
+
|
|
42
|
+
[tool.setuptools]
|
|
43
|
+
package-dir = { "" = "." }
|