dfm-python 0.5.56__tar.gz → 0.5.57__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.
- {dfm_python-0.5.56 → dfm_python-0.5.57}/PKG-INFO +4 -5
- {dfm_python-0.5.56 → dfm_python-0.5.57}/README.md +3 -3
- {dfm_python-0.5.56 → dfm_python-0.5.57}/config/ddfm_macro.yaml +22 -21
- {dfm_python-0.5.56 → dfm_python-0.5.57}/config/dfm_macro.yaml +24 -22
- {dfm_python-0.5.56 → dfm_python-0.5.57}/pyproject.toml +2 -1
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/__init__.py +3 -10
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/adapter.py +63 -7
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/constants.py +5 -4
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/schema/__init__.py +2 -6
- dfm_python-0.5.57/src/dfm_python/config/schema/block.py +122 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/schema/model.py +11 -2
- dfm_python-0.5.57/src/dfm_python/config/schema/params.py +279 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/schema/results.py +8 -74
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/config/types.py +3 -11
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/dataset/ddfm_dataset.py +35 -13
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/dataset/dfm_dataset.py +9 -1
- dfm_python-0.5.57/src/dfm_python/functional/__init__.py +11 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/functional/dfm_block.py +65 -14
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/functional/em.py +580 -223
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/logger/__init__.py +6 -12
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/logger/inference_logger.py +3 -17
- dfm_python-0.5.57/src/dfm_python/logger/logger.py +271 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/logger/train_logger.py +26 -34
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/models/__init__.py +2 -2
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/models/base.py +8 -29
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/models/ddfm.py +103 -3
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/models/dfm.py +486 -219
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/estimator.py +146 -26
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/stability.py +55 -151
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/tent.py +16 -6
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/validator.py +1 -2
- dfm_python-0.5.57/src/dfm_python/ssm/__init__.py +29 -0
- dfm_python-0.5.57/src/dfm_python/ssm/kalman.py +564 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/checkpoint.py +1 -1
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/misc.py +4 -10
- dfm_python-0.5.57/src/dfm_python/utils/validation.py +54 -0
- dfm_python-0.5.57/src/test/config/schema/test_model.py +61 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/schema/test_results.py +41 -58
- dfm_python-0.5.57/src/test/config/test_adapter.py +231 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/functional/test_dfm_block.py +17 -20
- dfm_python-0.5.57/src/test/functional/test_em.py +878 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/logger/test_inference_logger.py +4 -4
- dfm_python-0.5.57/src/test/logger/test_logger.py +146 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/logger/test_train_logger.py +4 -4
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/test_dfm.py +88 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/numeric/test_builder.py +2 -1
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/numeric/test_estimator.py +4 -3
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/numeric/test_stability.py +51 -50
- dfm_python-0.5.57/src/test/numeric/test_tent.py +135 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_finance_dfm.py +1 -1
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_macro_dfm.py +1 -1
- {dfm_python-0.5.56 → dfm_python-0.5.57}/uv.lock +1 -1
- dfm_python-0.5.56/LICENSE +0 -21
- dfm_python-0.5.56/src/dfm_python/config/schema/block.py +0 -64
- dfm_python-0.5.56/src/dfm_python/config/schema/params.py +0 -94
- dfm_python-0.5.56/src/dfm_python/functional/__init__.py +0 -13
- dfm_python-0.5.56/src/dfm_python/functional/irf.py +0 -305
- dfm_python-0.5.56/src/dfm_python/functional/krylov.py +0 -124
- dfm_python-0.5.56/src/dfm_python/logger/logger.py +0 -147
- dfm_python-0.5.56/src/dfm_python/ssm/__init__.py +0 -19
- dfm_python-0.5.56/src/dfm_python/ssm/arma.py +0 -0
- dfm_python-0.5.56/src/dfm_python/ssm/companion.py +0 -995
- dfm_python-0.5.56/src/dfm_python/ssm/kalman.py +0 -433
- dfm_python-0.5.56/src/dfm_python/ssm/structural.py +0 -298
- dfm_python-0.5.56/src/dfm_python/utils/validation.py +0 -121
- dfm_python-0.5.56/src/test/config/schema/test_model.py +0 -22
- dfm_python-0.5.56/src/test/config/test_adapter.py +0 -90
- dfm_python-0.5.56/src/test/functional/test_em.py +0 -57
- dfm_python-0.5.56/src/test/logger/test_logger.py +0 -28
- dfm_python-0.5.56/src/test/numeric/test_tent.py +0 -69
- {dfm_python-0.5.56 → dfm_python-0.5.57}/.git +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/.gitignore +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/.python-version +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/MANIFEST.in +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/config/ddfm_exchange.yaml +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/config/ddfm_finance.yaml +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/config/dfm_finance.yaml +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/data/exchange_rate.csv +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/data/finance.csv +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/data/macro.csv +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/dataset/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/dataset/time.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/decoder/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/decoder/base.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/decoder/linear.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/decoder/mlp.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/encoder/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/encoder/base.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/encoder/pca.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/encoder/simple_autoencoder.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/builder.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/numeric/statistic.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/errors.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/helper.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/loss.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/dfm_python/utils/metric.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/schema/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/schema/test_block.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/test_constants.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/config/test_types.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/conftest.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/dataset/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/dataset/test_dataloader.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/dataset/test_dataset.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/dataset/test_process.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/decoder/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/decoder/test_linear.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/decoder/test_mlp.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/encoder/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/encoder/test_base.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/encoder/test_pca.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/encoder/test_simple_encoder.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/functional/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/logger/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/test_base.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/test_ddfm.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/test_ddfm_batchnorm_placement.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/models/test_tensorflow_batchnorm_comparison.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/numeric/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/numeric/test_validator.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/ssm/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/ssm/test_arma.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/ssm/test_companion.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/ssm/test_kalman.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/ssm/test_structural.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/__init__.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_common.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_errors.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_helper.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_metric.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_misc.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_tensor_utils.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/src/test/utils/test_validation.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_exchange_ddfm.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_finance_ddfm.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_illness_ddfm.py +0 -0
- {dfm_python-0.5.56 → dfm_python-0.5.57}/tutorial/tutorial_macro_ddfm.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dfm-python
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.57
|
|
4
4
|
Summary: Dynamic Factor Model (DFM) estimation and forecasting in Python
|
|
5
5
|
Project-URL: Homepage, https://github.com/yourusername/dfm-python
|
|
6
6
|
Project-URL: Documentation, https://github.com/yourusername/dfm-python#readme
|
|
@@ -8,7 +8,6 @@ Project-URL: Repository, https://github.com/yourusername/dfm-python
|
|
|
8
8
|
Project-URL: Issues, https://github.com/yourusername/dfm-python/issues
|
|
9
9
|
Author: Minkey Chang
|
|
10
10
|
License: MIT
|
|
11
|
-
License-File: LICENSE
|
|
12
11
|
Keywords: dfm,dynamic-factor-model,econometrics,forecasting,time-series
|
|
13
12
|
Classifier: Development Status :: 4 - Beta
|
|
14
13
|
Classifier: Intended Audience :: Science/Research
|
|
@@ -176,7 +175,7 @@ dfm-python/
|
|
|
176
175
|
│ └── dfm_python/
|
|
177
176
|
│ ├── models/ # Model implementations (DFM, DDFM, KDFM)
|
|
178
177
|
│ ├── config/ # Configuration schemas
|
|
179
|
-
│ ├── datamodule/ #
|
|
178
|
+
│ ├── datamodule/ # Data loading and preprocessing modules
|
|
180
179
|
│ ├── trainer/ # Training procedures
|
|
181
180
|
│ ├── ssm/ # State-space model components
|
|
182
181
|
│ ├── dataset/ # Data loading and preprocessing
|
|
@@ -194,7 +193,7 @@ dfm-python/
|
|
|
194
193
|
- **Structural identification**: Learnable structural shock identification (Cholesky, full, low-rank)
|
|
195
194
|
- **Efficient computation**: Krylov FFT for O(T log T) forward pass
|
|
196
195
|
- **Direct IRF computation**: Avoids numerical error accumulation
|
|
197
|
-
- **Gradient descent training**: Uses PyTorch
|
|
196
|
+
- **Gradient descent training**: Uses PyTorch for training with custom logging
|
|
198
197
|
|
|
199
198
|
### DFM (Dynamic Factor Model)
|
|
200
199
|
|
|
@@ -207,7 +206,7 @@ dfm-python/
|
|
|
207
206
|
|
|
208
207
|
- **Nonlinear encoder**: Neural network encoder for nonlinear factor extraction
|
|
209
208
|
- **MCMC training**: Denoising training procedure
|
|
210
|
-
- **PyTorch-based**: Full PyTorch implementation with
|
|
209
|
+
- **PyTorch-based**: Full PyTorch implementation with custom logging system
|
|
211
210
|
|
|
212
211
|
## IRF Analysis: KDFM's PRIMARY CONTRIBUTION
|
|
213
212
|
|
|
@@ -118,7 +118,7 @@ dfm-python/
|
|
|
118
118
|
│ └── dfm_python/
|
|
119
119
|
│ ├── models/ # Model implementations (DFM, DDFM, KDFM)
|
|
120
120
|
│ ├── config/ # Configuration schemas
|
|
121
|
-
│ ├── datamodule/ #
|
|
121
|
+
│ ├── datamodule/ # Data loading and preprocessing modules
|
|
122
122
|
│ ├── trainer/ # Training procedures
|
|
123
123
|
│ ├── ssm/ # State-space model components
|
|
124
124
|
│ ├── dataset/ # Data loading and preprocessing
|
|
@@ -136,7 +136,7 @@ dfm-python/
|
|
|
136
136
|
- **Structural identification**: Learnable structural shock identification (Cholesky, full, low-rank)
|
|
137
137
|
- **Efficient computation**: Krylov FFT for O(T log T) forward pass
|
|
138
138
|
- **Direct IRF computation**: Avoids numerical error accumulation
|
|
139
|
-
- **Gradient descent training**: Uses PyTorch
|
|
139
|
+
- **Gradient descent training**: Uses PyTorch for training with custom logging
|
|
140
140
|
|
|
141
141
|
### DFM (Dynamic Factor Model)
|
|
142
142
|
|
|
@@ -149,7 +149,7 @@ dfm-python/
|
|
|
149
149
|
|
|
150
150
|
- **Nonlinear encoder**: Neural network encoder for nonlinear factor extraction
|
|
151
151
|
- **MCMC training**: Denoising training procedure
|
|
152
|
-
- **PyTorch-based**: Full PyTorch implementation with
|
|
152
|
+
- **PyTorch-based**: Full PyTorch implementation with custom logging system
|
|
153
153
|
|
|
154
154
|
## IRF Analysis: KDFM's PRIMARY CONTRIBUTION
|
|
155
155
|
|
|
@@ -26,29 +26,30 @@ target_scaler: standard # Scaler for target series: 'standard', 'robust', 'minm
|
|
|
26
26
|
|
|
27
27
|
# Frequency mapping for mixed-frequency macro data
|
|
28
28
|
# Clock is weekly (w), so monthly series are slower frequency
|
|
29
|
-
#
|
|
29
|
+
# Grouped format: frequencies are specified as lists grouped by frequency code
|
|
30
30
|
# Reduced set for faster testing (~50% reduction: 12 monthly series kept from original ~24)
|
|
31
31
|
frequency:
|
|
32
32
|
# Monthly series (slower than weekly clock) - typically end-of-month observations
|
|
33
33
|
# Essential series for testing
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
#
|
|
46
|
-
|
|
34
|
+
m:
|
|
35
|
+
- KOEMPTOTO # Total employment (monthly)
|
|
36
|
+
- KOHWRWEMP # Hours worked (monthly)
|
|
37
|
+
- KOIMPCONA # Investment, Construction (monthly)
|
|
38
|
+
- KOWRCCNSE # Consumption (monthly)
|
|
39
|
+
- KOCONPRCF # Production (monthly)
|
|
40
|
+
- KOCPCOREF # Consumer prices (monthly)
|
|
41
|
+
- KOCPEXFEF # Export prices (monthly)
|
|
42
|
+
- KOCREU..A # Credit (monthly)
|
|
43
|
+
- KOLRLTHH # Interest rates (monthly)
|
|
44
|
+
- KOBSIHAPR # Business survey (monthly)
|
|
45
|
+
- KOCNFCONR # Confidence (monthly)
|
|
46
|
+
- KOEQUIPTE # Investment, Equipment (monthly, target series)
|
|
47
47
|
# Weekly series (same as clock frequency)
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
w:
|
|
49
|
+
- KORFBEV # Retail, Food & Beverages (weekly)
|
|
50
|
+
- KORWHLS # Retail, Wholesale (weekly)
|
|
51
|
+
- KORMCMP # Retail, Miscellaneous & Comparison (weekly)
|
|
52
|
+
- KORELEC # Retail, Electronics (weekly)
|
|
53
|
+
- KORCNST # Retail, Construction (weekly)
|
|
54
|
+
- KORMACH # Retail, Machinery (weekly)
|
|
55
|
+
- KOROCOINF # Retail, Other Consumer & Information (weekly)
|
|
@@ -55,30 +55,32 @@ blocks:
|
|
|
55
55
|
|
|
56
56
|
# Frequency mapping for mixed-frequency macro data
|
|
57
57
|
# Clock is weekly (w), so monthly series are slower frequency
|
|
58
|
-
#
|
|
58
|
+
# Grouped format: frequencies are specified as lists grouped by frequency code
|
|
59
59
|
# Reduced set for faster testing (~50% reduction: 18 monthly series kept from original ~36)
|
|
60
60
|
frequency:
|
|
61
61
|
# Monthly series (slower than weekly clock) - typically end-of-month observations
|
|
62
62
|
# Block_Real series
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
#
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
#
|
|
76
|
-
|
|
63
|
+
m:
|
|
64
|
+
- KOEMPTOTO # Total employment (monthly)
|
|
65
|
+
- KOHWRWEMP # Hours worked (monthly)
|
|
66
|
+
- KOIMPCONA # Investment, Construction (monthly)
|
|
67
|
+
- KOWRCCNSE # Consumption (monthly)
|
|
68
|
+
- KOCONPRCF # Production (monthly)
|
|
69
|
+
# Block_Prices_Financial series
|
|
70
|
+
- KOCPCOREF # Consumer prices (monthly)
|
|
71
|
+
- KOCPEXFEF # Export prices (monthly)
|
|
72
|
+
- KOCREU..A # Credit (monthly)
|
|
73
|
+
- KOLRLTHH # Interest rates (monthly)
|
|
74
|
+
- KOBSIHAPR # Business survey (monthly)
|
|
75
|
+
- KOCNFCONR # Confidence (monthly)
|
|
76
|
+
# Target series
|
|
77
|
+
- KOEQUIPTE # Investment, Equipment (monthly, target series)
|
|
77
78
|
# Weekly series (same as clock frequency)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
79
|
+
w:
|
|
80
|
+
- KORFBEV # Retail, Food & Beverages (weekly)
|
|
81
|
+
- KORWHLS # Retail, Wholesale (weekly)
|
|
82
|
+
- KORMCMP # Retail, Miscellaneous & Comparison (weekly)
|
|
83
|
+
- KORELEC # Retail, Electronics (weekly)
|
|
84
|
+
- KORCNST # Retail, Construction (weekly)
|
|
85
|
+
- KORMACH # Retail, Machinery (weekly)
|
|
86
|
+
- KOROCOINF # Retail, Other Consumer & Information (weekly)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dfm-python"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.57"
|
|
4
4
|
description = "Dynamic Factor Model (DFM) estimation and forecasting in Python"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.10"
|
|
@@ -83,6 +83,7 @@ packages = [
|
|
|
83
83
|
exclude = [
|
|
84
84
|
"test_venv",
|
|
85
85
|
"test_venv/**",
|
|
86
|
+
"LICENSE",
|
|
86
87
|
]
|
|
87
88
|
|
|
88
89
|
[dependency-groups]
|
|
@@ -10,7 +10,7 @@ Note: Series are specified via frequency dict mapping column names to frequencie
|
|
|
10
10
|
from .schema import (
|
|
11
11
|
BaseModelConfig, DFMConfig, DDFMConfig,
|
|
12
12
|
BaseResult, DFMResult, DDFMResult,
|
|
13
|
-
|
|
13
|
+
DFMStateSpaceParams, DDFMStateSpaceParams,
|
|
14
14
|
)
|
|
15
15
|
# DEFAULT_BLOCK_NAME is imported lazily where needed to avoid circular imports
|
|
16
16
|
from .constants import (
|
|
@@ -46,8 +46,6 @@ from .types import (
|
|
|
46
46
|
ForecastResult,
|
|
47
47
|
CoefficientMatrix,
|
|
48
48
|
CovarianceMatrix,
|
|
49
|
-
IRFArray,
|
|
50
|
-
CompanionMatrix,
|
|
51
49
|
SeriesID,
|
|
52
50
|
Frequency,
|
|
53
51
|
DatasetName,
|
|
@@ -58,7 +56,6 @@ from .types import (
|
|
|
58
56
|
ResultDict,
|
|
59
57
|
ForecastDict,
|
|
60
58
|
MetricsDict,
|
|
61
|
-
IRFResultDict,
|
|
62
59
|
CheckpointDict,
|
|
63
60
|
ConfigDict,
|
|
64
61
|
Device,
|
|
@@ -107,9 +104,8 @@ __all__ = [
|
|
|
107
104
|
# 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import - import directly from functional.dfm_block
|
|
108
105
|
# Model-specific configs (from schema.py)
|
|
109
106
|
'DFMConfig', 'DDFMConfig',
|
|
110
|
-
#
|
|
111
|
-
'
|
|
112
|
-
'FitParams', # Backward compatibility alias
|
|
107
|
+
# State-space parameters
|
|
108
|
+
'DFMStateSpaceParams', 'DDFMStateSpaceParams',
|
|
113
109
|
# Model-specific results (from results.py)
|
|
114
110
|
'DFMResult', 'DDFMResult',
|
|
115
111
|
# Utilities
|
|
@@ -139,8 +135,6 @@ __all__ = [
|
|
|
139
135
|
'ForecastResult',
|
|
140
136
|
'CoefficientMatrix',
|
|
141
137
|
'CovarianceMatrix',
|
|
142
|
-
'IRFArray',
|
|
143
|
-
'CompanionMatrix',
|
|
144
138
|
'SeriesID',
|
|
145
139
|
'Frequency',
|
|
146
140
|
'DatasetName',
|
|
@@ -151,7 +145,6 @@ __all__ = [
|
|
|
151
145
|
'ResultDict',
|
|
152
146
|
'ForecastDict',
|
|
153
147
|
'MetricsDict',
|
|
154
|
-
'IRFResultDict',
|
|
155
148
|
'CheckpointDict',
|
|
156
149
|
'ConfigDict',
|
|
157
150
|
'Device',
|
|
@@ -118,7 +118,12 @@ def _extract_frequency_dict(
|
|
|
118
118
|
data: Dict[str, Any],
|
|
119
119
|
clock: str = DEFAULT_CLOCK_FREQUENCY
|
|
120
120
|
) -> Optional[Dict[str, str]]:
|
|
121
|
-
"""Extract frequency dict from data, handling
|
|
121
|
+
"""Extract frequency dict from data, handling multiple formats.
|
|
122
|
+
|
|
123
|
+
Supports:
|
|
124
|
+
1. Grouped format: {'w': [series1, series2, ...], 'm': [series3, ...]}
|
|
125
|
+
2. Individual format: {'series1': 'w', 'series2': 'm', ...}
|
|
126
|
+
3. Legacy format: {'series': [{'series_id': ..., 'frequency': ...}, ...]}
|
|
122
127
|
|
|
123
128
|
Parameters
|
|
124
129
|
----------
|
|
@@ -132,12 +137,63 @@ def _extract_frequency_dict(
|
|
|
132
137
|
Optional[Dict[str, str]]
|
|
133
138
|
Frequency dict mapping column names to frequencies, or None if not found
|
|
134
139
|
"""
|
|
135
|
-
if 'frequency' in data:
|
|
136
|
-
#
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
if 'frequency' not in data:
|
|
141
|
+
# Legacy: check for 'series' key
|
|
142
|
+
if 'series' in data:
|
|
143
|
+
return _convert_series_to_frequency_dict(data['series'], clock)
|
|
144
|
+
return None
|
|
145
|
+
|
|
146
|
+
freq_data = data['frequency']
|
|
147
|
+
|
|
148
|
+
# Check if it's in grouped format: {'w': [...], 'm': [...]}
|
|
149
|
+
if _is_dict_like(freq_data):
|
|
150
|
+
from .constants import VALID_FREQUENCIES
|
|
151
|
+
|
|
152
|
+
# Check if all keys are valid frequency codes (grouped format)
|
|
153
|
+
keys_are_frequencies = all(
|
|
154
|
+
isinstance(k, str) and k in VALID_FREQUENCIES
|
|
155
|
+
for k in freq_data.keys()
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
# Check if values are lists (grouped format)
|
|
159
|
+
values_are_lists = all(
|
|
160
|
+
isinstance(v, (list, tuple)) for v in freq_data.values()
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
if keys_are_frequencies and values_are_lists:
|
|
164
|
+
# Grouped format: convert to individual format
|
|
165
|
+
result = {}
|
|
166
|
+
for freq, series_list in freq_data.items():
|
|
167
|
+
if not isinstance(series_list, (list, tuple)):
|
|
168
|
+
_raise_config_error(
|
|
169
|
+
f"Frequency '{freq}' must map to a list of series names, got {type(series_list)}"
|
|
170
|
+
)
|
|
171
|
+
for series_name in series_list:
|
|
172
|
+
if not isinstance(series_name, str):
|
|
173
|
+
_raise_config_error(
|
|
174
|
+
f"Series names must be strings, got {type(series_name)} in frequency '{freq}'"
|
|
175
|
+
)
|
|
176
|
+
if series_name in result:
|
|
177
|
+
_raise_config_error(
|
|
178
|
+
f"Series '{series_name}' appears in multiple frequency groups"
|
|
179
|
+
)
|
|
180
|
+
result[series_name] = freq
|
|
181
|
+
return result
|
|
182
|
+
else:
|
|
183
|
+
# Individual format: already in correct format, validate structure
|
|
184
|
+
result = {}
|
|
185
|
+
for series_name, freq in freq_data.items():
|
|
186
|
+
if not isinstance(series_name, str):
|
|
187
|
+
_raise_config_error(
|
|
188
|
+
f"Frequency dict keys must be strings (series names), got {type(series_name)}"
|
|
189
|
+
)
|
|
190
|
+
if not isinstance(freq, str):
|
|
191
|
+
_raise_config_error(
|
|
192
|
+
f"Frequency dict values must be strings (frequency codes), got {type(freq)} for series '{series_name}'"
|
|
193
|
+
)
|
|
194
|
+
result[series_name] = freq
|
|
195
|
+
return result
|
|
196
|
+
|
|
141
197
|
return None
|
|
142
198
|
|
|
143
199
|
|
|
@@ -23,7 +23,7 @@ DEFAULT_MIN_DELTA = 1e-6 # Minimum change for improvement
|
|
|
23
23
|
# ============================================================================
|
|
24
24
|
|
|
25
25
|
# Minimum eigenvalues and variances
|
|
26
|
-
MIN_EIGENVALUE = 1e-
|
|
26
|
+
MIN_EIGENVALUE = 1e-6 # Minimum eigenvalue for positive definite matrices (increased from 1e-8 for better conditioning)
|
|
27
27
|
MIN_DIAGONAL_VARIANCE = 1e-8 # Minimum variance for diagonal elements
|
|
28
28
|
MIN_OBSERVATION_NOISE = 1e-4 # Minimum observation noise for measurement error (used in EM updates)
|
|
29
29
|
DEFAULT_DDFM_OBSERVATION_NOISE = 1e-15 # Default observation noise for DDFM state-space (matches original TensorFlow)
|
|
@@ -33,7 +33,7 @@ MIN_STD_FOR_SCALE_CHECK = 1e-10 # Minimum standard deviation for scale ratio co
|
|
|
33
33
|
DEFAULT_VARIANCE_FALLBACK = 1.0 # Default variance fallback value for numerical stability
|
|
34
34
|
|
|
35
35
|
# Maximum eigenvalues
|
|
36
|
-
MAX_EIGENVALUE =
|
|
36
|
+
MAX_EIGENVALUE = 1e3 # Maximum eigenvalue cap (reduced to 1e3 to improve condition number: 1e3/1e-6 = 1e9)
|
|
37
37
|
|
|
38
38
|
# Eigenvalue stability thresholds
|
|
39
39
|
DEFAULT_EIGENVALUE_MAX_MAGNITUDE = 1.0 # Default maximum eigenvalue magnitude for stability checks
|
|
@@ -217,6 +217,7 @@ DEFAULT_START_DATE = datetime(2000, 1, 1)
|
|
|
217
217
|
# Default window size for DDFM
|
|
218
218
|
DEFAULT_WINDOW_SIZE = 100
|
|
219
219
|
DEFAULT_TENT_KERNEL_SIZE = 5 # Default tent kernel size for slower-frequency series aggregation
|
|
220
|
+
DEFAULT_TENT_KERNEL_REGULARIZATION_MULTIPLIER = 100.0 # Regularization multiplier for tent kernel series (handles ill-conditioning)
|
|
220
221
|
# Note: DEFAULT_BATCH_SIZE is defined above (line 88) as 32 for general neural networks
|
|
221
222
|
# Use DEFAULT_DDFM_WINDOW_SIZE (100) for DDFM-specific window size (time-step batch size)
|
|
222
223
|
|
|
@@ -284,7 +285,7 @@ DEFAULT_PROGRESS_LOG_INTERVAL = 5 # Default progress logging interval for EM al
|
|
|
284
285
|
# Precision Defaults
|
|
285
286
|
# ============================================================================
|
|
286
287
|
|
|
287
|
-
DEFAULT_DTYPE = np.
|
|
288
|
+
DEFAULT_DTYPE = np.float64 # Default numpy dtype for arrays (float64 for better numerical stability)
|
|
288
289
|
|
|
289
290
|
# PyTorch dtype (matches DEFAULT_DTYPE)
|
|
290
291
|
try:
|
|
@@ -518,7 +519,6 @@ __all__ = [
|
|
|
518
519
|
'MIN_VARIABLES',
|
|
519
520
|
'MIN_SHAPE_FOR_AR2',
|
|
520
521
|
'MIN_DDFM_TIME_STEPS',
|
|
521
|
-
'MIN_SHAPE_FOR_AR2',
|
|
522
522
|
'MIN_DDFM_DATASET_SIZE_WARNING',
|
|
523
523
|
'MIN_ITER_FOR_DELTA_COMPUTATION',
|
|
524
524
|
'DEFAULT_MIN_ITER_FOR_CONVERGENCE_CHECK',
|
|
@@ -546,6 +546,7 @@ __all__ = [
|
|
|
546
546
|
'DEFAULT_LOG_INTERVAL',
|
|
547
547
|
'DEFAULT_PROGRESS_LOG_INTERVAL',
|
|
548
548
|
'DEFAULT_TENT_KERNEL_SIZE',
|
|
549
|
+
'DEFAULT_TENT_KERNEL_REGULARIZATION_MULTIPLIER',
|
|
549
550
|
'MAX_ERROR_ITEMS',
|
|
550
551
|
# IRF
|
|
551
552
|
'DEFAULT_IRF_HORIZON',
|
|
@@ -9,15 +9,11 @@ Note: Series are specified via frequency dict mapping column names to frequencie
|
|
|
9
9
|
|
|
10
10
|
from .model import BaseModelConfig, DFMConfig, DDFMConfig
|
|
11
11
|
from .results import BaseResult, DFMResult, DDFMResult
|
|
12
|
-
from .params import
|
|
13
|
-
|
|
14
|
-
# Backward compatibility alias
|
|
15
|
-
FitParams = DFMFitParams
|
|
12
|
+
from .params import DFMStateSpaceParams, DDFMStateSpaceParams
|
|
16
13
|
|
|
17
14
|
__all__ = [
|
|
18
15
|
'BaseModelConfig', 'DFMConfig', 'DDFMConfig',
|
|
19
16
|
'BaseResult', 'DFMResult', 'DDFMResult',
|
|
20
|
-
'
|
|
21
|
-
'FitParams', # Backward compatibility alias
|
|
17
|
+
'DFMStateSpaceParams', 'DDFMStateSpaceParams',
|
|
22
18
|
]
|
|
23
19
|
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"""Block structure configuration for DFM.
|
|
2
|
+
|
|
3
|
+
This module defines the BlockStructure dataclass used to group block-related
|
|
4
|
+
parameters in EM algorithm, replacing long conditional checks with a single
|
|
5
|
+
optional parameter.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
from typing import Optional, Dict, List
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class BlockStructure:
|
|
15
|
+
"""Block structure configuration for EM algorithm.
|
|
16
|
+
|
|
17
|
+
Groups all block-related parameters together to simplify function signatures
|
|
18
|
+
and replace long conditional checks.
|
|
19
|
+
|
|
20
|
+
Attributes
|
|
21
|
+
----------
|
|
22
|
+
blocks : np.ndarray
|
|
23
|
+
Block structure array (N x n_blocks)
|
|
24
|
+
r : np.ndarray
|
|
25
|
+
Number of factors per block (n_blocks,)
|
|
26
|
+
p : int
|
|
27
|
+
VAR lag order
|
|
28
|
+
p_plus_one : int
|
|
29
|
+
State dimension per factor. This is equal to max_lag_size = max(p + 1, tent_kernel_size).
|
|
30
|
+
The name "p_plus_one" is used for backward compatibility with the EM algorithm interface.
|
|
31
|
+
In the model code, this is called "max_lag_size" to more clearly indicate it accounts
|
|
32
|
+
for tent kernel size when tent_kernel_size > p + 1.
|
|
33
|
+
n_clock_freq : int
|
|
34
|
+
Number of clock-frequency series
|
|
35
|
+
idio_indicator : np.ndarray
|
|
36
|
+
Idiosyncratic component indicator (N,)
|
|
37
|
+
R_mat : np.ndarray, optional
|
|
38
|
+
Tent kernel constraint matrix for mixed-frequency data
|
|
39
|
+
q : np.ndarray, optional
|
|
40
|
+
Tent kernel constraint vector for mixed-frequency data
|
|
41
|
+
n_slower_freq : int, optional
|
|
42
|
+
Number of slower-frequency series
|
|
43
|
+
tent_weights_dict : dict, optional
|
|
44
|
+
Dictionary mapping frequency pairs to tent weights
|
|
45
|
+
|
|
46
|
+
Cached indices (computed once, reused across EM iterations):
|
|
47
|
+
_cached_unique_blocks : List[np.ndarray], optional
|
|
48
|
+
Unique block patterns (cached)
|
|
49
|
+
_cached_unique_indices : List[int], optional
|
|
50
|
+
Indices of unique block patterns (cached)
|
|
51
|
+
_cached_bl_idxM : List[np.ndarray], optional
|
|
52
|
+
Clock-frequency factor loadings indices per unique block pattern (cached)
|
|
53
|
+
_cached_bl_idxQ : List[np.ndarray], optional
|
|
54
|
+
Slower-frequency factor loadings indices per unique block pattern (cached)
|
|
55
|
+
_cached_R_con : np.ndarray, optional
|
|
56
|
+
Block diagonal constraint matrix (cached)
|
|
57
|
+
_cached_q_con : np.ndarray, optional
|
|
58
|
+
Constraint vector (cached)
|
|
59
|
+
_cached_total_factor_dim : int, optional
|
|
60
|
+
Total factor state dimension (cached)
|
|
61
|
+
_cached_idio_indicator_M : np.ndarray, optional
|
|
62
|
+
Clock-frequency idiosyncratic component indicator (cached)
|
|
63
|
+
_cached_n_idio_M : int, optional
|
|
64
|
+
Number of clock-frequency idiosyncratic components (cached)
|
|
65
|
+
_cached_c_idio_indicator : np.ndarray, optional
|
|
66
|
+
Cumulative sum of idiosyncratic component indicator (cached)
|
|
67
|
+
_cached_rp1 : int, optional
|
|
68
|
+
Start of idiosyncratic components in state space (cached)
|
|
69
|
+
"""
|
|
70
|
+
blocks: np.ndarray
|
|
71
|
+
r: np.ndarray
|
|
72
|
+
p: int
|
|
73
|
+
p_plus_one: int
|
|
74
|
+
n_clock_freq: int
|
|
75
|
+
idio_indicator: np.ndarray
|
|
76
|
+
R_mat: Optional[np.ndarray] = None
|
|
77
|
+
q: Optional[np.ndarray] = None
|
|
78
|
+
n_slower_freq: Optional[int] = None
|
|
79
|
+
tent_weights_dict: Optional[Dict[str, np.ndarray]] = None
|
|
80
|
+
|
|
81
|
+
# Cached indices (computed once, reused across EM iterations)
|
|
82
|
+
_cached_unique_blocks: Optional[List[np.ndarray]] = field(default=None, init=False, repr=False)
|
|
83
|
+
_cached_unique_indices: Optional[List[int]] = field(default=None, init=False, repr=False)
|
|
84
|
+
_cached_bl_idxM: Optional[List[np.ndarray]] = field(default=None, init=False, repr=False)
|
|
85
|
+
_cached_bl_idxQ: Optional[List[np.ndarray]] = field(default=None, init=False, repr=False)
|
|
86
|
+
_cached_R_con: Optional[np.ndarray] = field(default=None, init=False, repr=False)
|
|
87
|
+
_cached_q_con: Optional[np.ndarray] = field(default=None, init=False, repr=False)
|
|
88
|
+
_cached_total_factor_dim: Optional[int] = field(default=None, init=False, repr=False)
|
|
89
|
+
_cached_idio_indicator_M: Optional[np.ndarray] = field(default=None, init=False, repr=False)
|
|
90
|
+
_cached_n_idio_M: Optional[int] = field(default=None, init=False, repr=False)
|
|
91
|
+
_cached_c_idio_indicator: Optional[np.ndarray] = field(default=None, init=False, repr=False)
|
|
92
|
+
_cached_rp1: Optional[int] = field(default=None, init=False, repr=False)
|
|
93
|
+
|
|
94
|
+
def is_valid(self) -> bool:
|
|
95
|
+
"""Check if block structure is valid (all required fields are not None)."""
|
|
96
|
+
return (
|
|
97
|
+
self.blocks is not None
|
|
98
|
+
and self.r is not None
|
|
99
|
+
and self.p is not None
|
|
100
|
+
and self.p_plus_one is not None
|
|
101
|
+
and self.n_clock_freq is not None
|
|
102
|
+
and self.idio_indicator is not None
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def has_cached_indices(self) -> bool:
|
|
106
|
+
"""Check if block structure indices are cached."""
|
|
107
|
+
return self._cached_unique_blocks is not None
|
|
108
|
+
|
|
109
|
+
def clear_cache(self) -> None:
|
|
110
|
+
"""Clear all cached indices to ensure clean state for new training runs."""
|
|
111
|
+
self._cached_unique_blocks = None
|
|
112
|
+
self._cached_unique_indices = None
|
|
113
|
+
self._cached_bl_idxM = None
|
|
114
|
+
self._cached_bl_idxQ = None
|
|
115
|
+
self._cached_R_con = None
|
|
116
|
+
self._cached_q_con = None
|
|
117
|
+
self._cached_total_factor_dim = None
|
|
118
|
+
self._cached_idio_indicator_M = None
|
|
119
|
+
self._cached_n_idio_M = None
|
|
120
|
+
self._cached_c_idio_indicator = None
|
|
121
|
+
self._cached_rp1 = None
|
|
122
|
+
|
|
@@ -91,7 +91,9 @@ class BaseModelConfig:
|
|
|
91
91
|
- Data preprocessing (missing data handling)
|
|
92
92
|
|
|
93
93
|
Series Configuration:
|
|
94
|
-
- Provide `frequency` dict
|
|
94
|
+
- Provide `frequency` dict in one of two formats:
|
|
95
|
+
1. Grouped format: {'w': [series1, series2, ...], 'm': [series3, ...]} (recommended for large configs)
|
|
96
|
+
2. Individual format: {'series1': 'w', 'series2': 'm', ...} (backward compatible)
|
|
95
97
|
- If `frequency` is None, all columns will use `clock` frequency
|
|
96
98
|
- If a column is missing from `frequency` dict, it will use `clock` frequency
|
|
97
99
|
- When data is loaded, missing columns in `frequency` dict are automatically added with `clock` frequency
|
|
@@ -103,7 +105,14 @@ class BaseModelConfig:
|
|
|
103
105
|
|
|
104
106
|
Examples
|
|
105
107
|
--------
|
|
106
|
-
>>> # With
|
|
108
|
+
>>> # With grouped frequency mapping (recommended for large configs)
|
|
109
|
+
>>> config = DFMConfig(
|
|
110
|
+
... frequency={'q': ['gdp'], 'm': ['unemployment', 'interest_rate']},
|
|
111
|
+
... clock='m',
|
|
112
|
+
... blocks={...}
|
|
113
|
+
... )
|
|
114
|
+
>>>
|
|
115
|
+
>>> # With individual frequency mapping (backward compatible)
|
|
107
116
|
>>> config = DFMConfig(
|
|
108
117
|
... frequency={'gdp': 'q', 'unemployment': 'm', 'interest_rate': 'm'},
|
|
109
118
|
... clock='m',
|