dfm-python 0.2.0__tar.gz → 0.2.1__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.2.1/CHANGELOG.md +216 -0
- dfm_python-0.2.1/PKG-INFO +310 -0
- dfm_python-0.2.1/README.md +266 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/pyproject.toml +1 -1
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/__init__.py +2 -2
- dfm_python-0.2.0/src/dfm_python/dfm_api.py → dfm_python-0.2.1/src/dfm_python/api.py +41 -251
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/config.py +72 -7
- dfm_python-0.2.1/src/dfm_python/core/__init__.py +59 -0
- dfm_python-0.2.1/src/dfm_python/core/diagnostics.py +274 -0
- dfm_python-0.2.1/src/dfm_python/core/em.py +1022 -0
- dfm_python-0.2.1/src/dfm_python/core/grouping.py +54 -0
- dfm_python-0.2.1/src/dfm_python/core/helpers.py +56 -0
- dfm_python-0.2.1/src/dfm_python/core/numeric.py +346 -0
- dfm_python-0.2.1/src/dfm_python/core/results.py +70 -0
- dfm_python-0.2.1/src/dfm_python/dfm.py +877 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/kalman.py +18 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/data_utils.py +3 -5
- dfm_python-0.2.1/src/test/test_api.py +251 -0
- dfm_python-0.2.1/src/test/test_config.py +296 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_dfm.py +19 -5
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_news.py +2 -1
- {dfm_python-0.2.0 → dfm_python-0.2.1}/tutorial/basic_tutorial.py +4 -4
- {dfm_python-0.2.0 → dfm_python-0.2.1}/tutorial/hydra_tutorial.py +7 -4
- dfm_python-0.2.0/CHANGELOG.md +0 -89
- dfm_python-0.2.0/PKG-INFO +0 -647
- dfm_python-0.2.0/README.md +0 -603
- dfm_python-0.2.0/src/dfm_python/dfm.py +0 -3918
- dfm_python-0.2.0/src/test/test_api_edge_cases.py +0 -295
- dfm_python-0.2.0/src/test/test_config_sources.py +0 -369
- dfm_python-0.2.0/src/test/test_convenience_api.py +0 -160
- dfm_python-0.2.0/src/test/test_tutorials.py +0 -288
- {dfm_python-0.2.0 → dfm_python-0.2.1}/.gitignore +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/.python-version +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/LICENSE +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/MANIFEST.in +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/config/blocks/default.yaml +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/config/default.yaml +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/config/series/default.yaml +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/data/sample_data.csv +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/data/sample_spec.csv +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/__init__.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/data_loader.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/news.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/__init__.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/aggregation.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/__init__.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_kalman.py +0 -0
- {dfm_python-0.2.0 → dfm_python-0.2.1}/uv.lock +0 -0
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [0.2.1] - 2025-01-XX
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Mixed Frequency Edge Case**: Fixed dimension mismatch in `init_conditions` when slower frequency idio components are added to `C` but not to `A`. Now properly creates `BQ`, `SQ`, and `initViQ` with correct dimensions.
|
|
8
|
+
- **UnboundLocalError**: Fixed `F` variable initialization in `init_conditions` to prevent `UnboundLocalError` when block initialization fails.
|
|
9
|
+
- **Kalman Filter**: Fixed `Y_t` initialization in `skf` to prevent `UnboundLocalError` when no observations are present.
|
|
10
|
+
- **MergedConfigSource**: Fixed handling of partial configuration dictionaries (e.g., only `max_iter` and `threshold`) to correctly merge with base configuration.
|
|
11
|
+
- **Tutorials**: Fixed pandas FutureWarning by updating `'M'` frequency to `'ME'` in both `basic_tutorial.py` and `hydra_tutorial.py`.
|
|
12
|
+
- **Test Suite**: Recreated `test_config.py` from scratch to fix indentation errors and align with new API.
|
|
13
|
+
|
|
14
|
+
### Documentation
|
|
15
|
+
|
|
16
|
+
- **README**: Significantly simplified and streamlined (reduced from 653 to ~250 lines) while maintaining all essential information.
|
|
17
|
+
- Improved clarity and focus on most common use cases.
|
|
18
|
+
|
|
19
|
+
## [0.2.0] - 2025-01-XX
|
|
20
|
+
|
|
21
|
+
### Major Refactoring
|
|
22
|
+
|
|
23
|
+
This release represents a comprehensive refactoring focused on code quality, maintainability, and robustness.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **Mixed Frequency Edge Case**: Fixed dimension mismatch in `init_conditions` when slower frequency idio components are added to `C` but not to `A`. Now properly creates `BQ`, `SQ`, and `initViQ` with correct dimensions.
|
|
28
|
+
- **UnboundLocalError**: Fixed `F` variable initialization in `init_conditions` to prevent `UnboundLocalError` when block initialization fails.
|
|
29
|
+
- **Kalman Filter**: Fixed `Y_t` initialization in `skf` to prevent `UnboundLocalError` when no observations are present.
|
|
30
|
+
- **MergedConfigSource**: Fixed handling of partial configuration dictionaries (e.g., only `max_iter` and `threshold`) to correctly merge with base configuration.
|
|
31
|
+
- **Tutorials**: Fixed pandas FutureWarning by updating `'M'` frequency to `'ME'` in both `basic_tutorial.py` and `hydra_tutorial.py`.
|
|
32
|
+
- **Test Suite**: Recreated `test_config.py` from scratch to fix indentation errors and align with new API.
|
|
33
|
+
|
|
34
|
+
#### Architecture Improvements
|
|
35
|
+
|
|
36
|
+
- **Class-Centric Design**: Complete migration from functional API to class-based design
|
|
37
|
+
- Removed deprecated `dfm()` function wrapper
|
|
38
|
+
- Core algorithm now in `DFM` class with `fit()` method
|
|
39
|
+
- Module-level convenience API for easy usage
|
|
40
|
+
- All legacy backward compatibility code removed
|
|
41
|
+
|
|
42
|
+
- **Modular Structure**: Reorganized code into focused `core` modules
|
|
43
|
+
- `core/em.py`: EM algorithm core (init_conditions, em_step, em_converged)
|
|
44
|
+
- `core/numeric.py`: Numerical utilities (matrix operations, regularization, clipping)
|
|
45
|
+
- `core/diagnostics.py`: Diagnostic functions and output formatting
|
|
46
|
+
- `core/results.py`: Result metrics (RMSE calculation)
|
|
47
|
+
- `core/grouping.py`: Frequency grouping utilities
|
|
48
|
+
- Removed 17 proxy functions, using direct imports for cleaner code
|
|
49
|
+
|
|
50
|
+
#### Code Quality Improvements
|
|
51
|
+
|
|
52
|
+
- **Exception Handling**: Replaced all generic `Exception` catches with specific numerical exception types
|
|
53
|
+
- Defined `_NUMERICAL_EXCEPTIONS` tuple for common numerical errors
|
|
54
|
+
- More specific error handling: `LinAlgError`, `ValueError`, `ZeroDivisionError`, `OverflowError`, `FloatingPointError`
|
|
55
|
+
- Better debugging and error tracking throughout the package
|
|
56
|
+
|
|
57
|
+
- **Logging**: Improved logging infrastructure
|
|
58
|
+
- Converted `print()` statements to proper logging in diagnostics module
|
|
59
|
+
- Added early return for performance when logging is disabled
|
|
60
|
+
- Consistent logging levels (info, warning, debug) across modules
|
|
61
|
+
- User-facing functions (e.g., `print_series_diagnosis`) still use `print()` for direct output
|
|
62
|
+
|
|
63
|
+
- **Import Optimization**: Cleaner import structure
|
|
64
|
+
- Moved pandas import to module top with availability check
|
|
65
|
+
- Removed redundant imports and circular dependencies
|
|
66
|
+
- Consistent import patterns across all modules
|
|
67
|
+
|
|
68
|
+
#### Code Simplification
|
|
69
|
+
|
|
70
|
+
- **Removed Redundancy**: Eliminated ~120 lines of redundant code
|
|
71
|
+
- Removed all proxy functions (17 total)
|
|
72
|
+
- Direct imports from core modules
|
|
73
|
+
- Cleaner, more maintainable codebase
|
|
74
|
+
|
|
75
|
+
- **Helper Functions**: Extracted common patterns into reusable helpers
|
|
76
|
+
- `_check_finite()`: Centralized NaN/Inf validation
|
|
77
|
+
- `_ensure_square_matrix()`: Matrix shape validation
|
|
78
|
+
- `_get_config_param()`: Centralized config parameter access
|
|
79
|
+
- `_resolve_param()`: Parameter override resolution
|
|
80
|
+
|
|
81
|
+
#### Type Safety
|
|
82
|
+
|
|
83
|
+
- **TypedDict**: Added `NaNHandlingOptions` TypedDict for type-safe NaN handling
|
|
84
|
+
- **Improved Type Hints**: Better type annotations throughout
|
|
85
|
+
- **TYPE_CHECKING**: Used for circular import resolution
|
|
86
|
+
|
|
87
|
+
#### Numerical Stability
|
|
88
|
+
|
|
89
|
+
- **Enhanced Validation**: Better validation of initial conditions and intermediate results
|
|
90
|
+
- **Improved Error Messages**: More descriptive error messages with context
|
|
91
|
+
- **Robust Fallbacks**: Better fallback mechanisms for numerical edge cases
|
|
92
|
+
|
|
93
|
+
### Changed
|
|
94
|
+
|
|
95
|
+
- **BREAKING**: Removed `dfm()` function - use `DFM().fit()` instead
|
|
96
|
+
- **BREAKING**: Removed deprecated `load_config_from_*` methods
|
|
97
|
+
- Module structure reorganized for better maintainability
|
|
98
|
+
- All diagnostic output now uses logging instead of print (except user-facing functions)
|
|
99
|
+
- Exception handling now catches specific exception types instead of generic `Exception`
|
|
100
|
+
|
|
101
|
+
### Added
|
|
102
|
+
|
|
103
|
+
- `_NUMERICAL_EXCEPTIONS` tuple for consistent exception handling
|
|
104
|
+
- `NaNHandlingOptions` TypedDict for type-safe NaN handling
|
|
105
|
+
- Helper functions for common patterns (`_check_finite`, `_ensure_square_matrix`, etc.)
|
|
106
|
+
- Early return optimization in diagnostics when logging is disabled
|
|
107
|
+
- Better error messages with context
|
|
108
|
+
|
|
109
|
+
### Removed
|
|
110
|
+
|
|
111
|
+
- Deprecated `dfm()` function wrapper
|
|
112
|
+
- All proxy functions (17 total) - now using direct imports
|
|
113
|
+
- Legacy backward compatibility code
|
|
114
|
+
- Redundant imports and circular dependencies
|
|
115
|
+
- ~120 lines of redundant code
|
|
116
|
+
|
|
117
|
+
### Fixed
|
|
118
|
+
|
|
119
|
+
- Improved exception handling specificity
|
|
120
|
+
- Better error messages for debugging
|
|
121
|
+
- Fixed import circular dependencies using TYPE_CHECKING
|
|
122
|
+
- Enhanced numerical stability validation
|
|
123
|
+
|
|
124
|
+
### Documentation
|
|
125
|
+
|
|
126
|
+
- Updated README to reflect new class-based API
|
|
127
|
+
- Updated all docstrings to use new API
|
|
128
|
+
- Improved code comments and documentation
|
|
129
|
+
|
|
130
|
+
## [0.1.7] - 2025-01-XX
|
|
131
|
+
|
|
132
|
+
### Changed
|
|
133
|
+
- **BREAKING**: Removed CSV config loading - use YAML files or create `DFMConfig` objects directly
|
|
134
|
+
- Made package more generic by removing application-specific dependencies
|
|
135
|
+
- Improved code documentation and comments throughout codebase
|
|
136
|
+
- Refactored variable naming for clarity and consistency
|
|
137
|
+
- Updated README to be more concise and focused
|
|
138
|
+
|
|
139
|
+
### Added
|
|
140
|
+
- Direct `DFMConfig` object creation support in `load_config()`
|
|
141
|
+
- Application-specific adapter guidance for custom formats
|
|
142
|
+
- Database-backed data loading adapter interface documentation
|
|
143
|
+
- Enhanced function docstrings with detailed parameter descriptions
|
|
144
|
+
|
|
145
|
+
### Removed
|
|
146
|
+
- CSV configuration file support (deprecated, use YAML or direct object creation)
|
|
147
|
+
- `load_config_from_csv()` function (deprecated, kept for backward compatibility with warning)
|
|
148
|
+
- Spec file dependencies
|
|
149
|
+
|
|
150
|
+
### Fixed
|
|
151
|
+
- Improved error messages for frequency constraint violations
|
|
152
|
+
- Enhanced type hints and documentation
|
|
153
|
+
|
|
154
|
+
## [0.1.6] - Previous release
|
|
155
|
+
|
|
156
|
+
### Changed
|
|
157
|
+
- Frequency generalization improvements
|
|
158
|
+
- Code cleanup and refactoring
|
|
159
|
+
|
|
160
|
+
## [0.1.5] - Previous release
|
|
161
|
+
|
|
162
|
+
### Changed
|
|
163
|
+
- Additional improvements and bug fixes
|
|
164
|
+
|
|
165
|
+
## [0.1.4] - 2024-11-07
|
|
166
|
+
|
|
167
|
+
### Fixed
|
|
168
|
+
- Fixed critical bug: `ff` variable scoping issue in `init_conditions()` causing dimension mismatch errors in multi-block models with different factor counts
|
|
169
|
+
- Fixed `A_temp` variable scoping issue that could cause incorrect computations when OLS regression fails for some blocks
|
|
170
|
+
- Fixed `bl_idxM` and `bl_idxQ` initialization issue that could cause AttributeError when no blocks are processed
|
|
171
|
+
- Removed unreachable code in `init_conditions()` else branch
|
|
172
|
+
- Improved empty array handling in `em_step()` for quarterly series constraints
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
- Enhanced variable scoping safety by resetting block-specific variables at start of each iteration
|
|
176
|
+
- Improved error handling for edge cases with empty arrays
|
|
177
|
+
|
|
178
|
+
## [0.1.3] - 2024-11-07
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
- Comprehensive README with detailed inputs/outputs documentation
|
|
182
|
+
- Clock-based mixed-frequency framework documentation
|
|
183
|
+
- Enhanced module-level docstrings throughout the codebase
|
|
184
|
+
- Detailed API reference with examples
|
|
185
|
+
- Improved error messages with context and solutions
|
|
186
|
+
|
|
187
|
+
### Changed
|
|
188
|
+
- Optimized code performance (removed redundant computations)
|
|
189
|
+
- Improved memory usage (replaced unnecessary copies with views)
|
|
190
|
+
- Enhanced code documentation and comments
|
|
191
|
+
- Updated package description and metadata
|
|
192
|
+
|
|
193
|
+
### Fixed
|
|
194
|
+
- Removed duplicate `frequencies_array` computation
|
|
195
|
+
- Fixed `optNaN` dictionary mutation issue
|
|
196
|
+
- Improved code organization and clarity
|
|
197
|
+
|
|
198
|
+
### Documentation
|
|
199
|
+
- Complete input/output specifications
|
|
200
|
+
- 5 comprehensive usage examples
|
|
201
|
+
- Troubleshooting guide with solutions
|
|
202
|
+
- Architecture overview
|
|
203
|
+
- Clock-based framework explanation
|
|
204
|
+
|
|
205
|
+
## [0.1.2] - Previous release
|
|
206
|
+
|
|
207
|
+
### Fixed
|
|
208
|
+
- Fixed `ModuleNotFoundError: No module named 'utils'` by moving utils into dfm_python package
|
|
209
|
+
- Improved import paths and package structure
|
|
210
|
+
|
|
211
|
+
## [0.1.1] - Initial release
|
|
212
|
+
|
|
213
|
+
- Initial PyPI release
|
|
214
|
+
- Core DFM estimation functionality
|
|
215
|
+
- Mixed-frequency data support
|
|
216
|
+
- News decomposition
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dfm-python
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: Dynamic Factor Model (DFM) estimation and nowcasting in Python
|
|
5
|
+
Project-URL: Homepage, https://github.com/yourusername/dfm-python
|
|
6
|
+
Project-URL: Documentation, https://github.com/yourusername/dfm-python#readme
|
|
7
|
+
Project-URL: Repository, https://github.com/yourusername/dfm-python
|
|
8
|
+
Project-URL: Issues, https://github.com/yourusername/dfm-python/issues
|
|
9
|
+
Author: DFM Python Contributors
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: dfm,dynamic-factor-model,econometrics,forecasting,nowcasting,time-series
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Scientific/Engineering
|
|
19
|
+
Requires-Python: >=3.12
|
|
20
|
+
Requires-Dist: hydra-core>=1.3.2
|
|
21
|
+
Requires-Dist: matplotlib>=3.10.7
|
|
22
|
+
Requires-Dist: numpy>=1.24.0
|
|
23
|
+
Requires-Dist: pandas>=2.0.0
|
|
24
|
+
Requires-Dist: scipy>=1.10.0
|
|
25
|
+
Provides-Extra: all
|
|
26
|
+
Requires-Dist: httpx>=0.24.0; extra == 'all'
|
|
27
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'all'
|
|
28
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'all'
|
|
29
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == 'all'
|
|
30
|
+
Requires-Dist: pydantic-settings>=2.11.0; extra == 'all'
|
|
31
|
+
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
32
|
+
Requires-Dist: supabase>=2.0.0; extra == 'all'
|
|
33
|
+
Provides-Extra: database
|
|
34
|
+
Requires-Dist: httpx>=0.24.0; extra == 'database'
|
|
35
|
+
Requires-Dist: psycopg2-binary>=2.9.0; extra == 'database'
|
|
36
|
+
Requires-Dist: pydantic-settings>=2.11.0; extra == 'database'
|
|
37
|
+
Requires-Dist: supabase>=2.0.0; extra == 'database'
|
|
38
|
+
Provides-Extra: dev
|
|
39
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
40
|
+
Provides-Extra: hydra
|
|
41
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'hydra'
|
|
42
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'hydra'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# dfm-python: Dynamic Factor Models for Python
|
|
46
|
+
|
|
47
|
+
[](https://pypi.org/project/dfm-python/)
|
|
48
|
+
[](https://www.python.org/downloads/)
|
|
49
|
+
|
|
50
|
+
A Python implementation of **Dynamic Factor Models (DFM)** for nowcasting and forecasting high-dimensional time series. Implements clock-based synchronization and tent kernel aggregation for mixed-frequency data.
|
|
51
|
+
|
|
52
|
+
## Features
|
|
53
|
+
|
|
54
|
+
- **Mixed-frequency data**: Monthly, quarterly, semi-annual, annual
|
|
55
|
+
- **Clock-based framework**: All factors evolve at a common clock frequency
|
|
56
|
+
- **Block structure**: Flexible factor organization (global, sector-specific)
|
|
57
|
+
- **Robust missing data**: Spline interpolation and Kalman filter handling
|
|
58
|
+
- **News decomposition**: Attribute forecast changes to data releases
|
|
59
|
+
- **Generic design**: YAML configs or direct object creation, extensible via adapters
|
|
60
|
+
|
|
61
|
+
## Installation
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pip install dfm-python
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**Requirements**: Python >= 3.12, numpy >= 1.24.0, pandas >= 2.0.0, scipy >= 1.10.0
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
### Module-Level API (Recommended)
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
import dfm_python as dfm
|
|
75
|
+
from dfm_python.config import Params
|
|
76
|
+
|
|
77
|
+
# 1. Load config from spec CSV + Params
|
|
78
|
+
params = Params(max_iter=5000, threshold=1e-5)
|
|
79
|
+
dfm.from_spec('data/sample_spec.csv', params=params)
|
|
80
|
+
|
|
81
|
+
# 2. Load data
|
|
82
|
+
dfm.load_data('data/sample_data.csv', sample_start='2021-01-01', sample_end='2022-12-31')
|
|
83
|
+
|
|
84
|
+
# 3. Train
|
|
85
|
+
dfm.train(max_iter=5000)
|
|
86
|
+
|
|
87
|
+
# 4. Forecast
|
|
88
|
+
X_forecast, Z_forecast = dfm.predict(horizon=12)
|
|
89
|
+
|
|
90
|
+
# 5. Plot
|
|
91
|
+
dfm.plot(kind='factor', factor_index=0, forecast_horizon=12, save_path='outputs/factor.png')
|
|
92
|
+
|
|
93
|
+
# 6. Access results
|
|
94
|
+
result = dfm.get_result()
|
|
95
|
+
factors = result.Z # (T × m) Smoothed factors
|
|
96
|
+
loadings = result.C # (N × m) Factor loadings
|
|
97
|
+
smoothed = result.X_sm # (T × N) Smoothed data
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Alternative: YAML Configuration
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
import dfm_python as dfm
|
|
104
|
+
|
|
105
|
+
# Load from YAML
|
|
106
|
+
dfm.from_yaml('config/default.yaml')
|
|
107
|
+
dfm.load_data('data/sample_data.csv')
|
|
108
|
+
dfm.train()
|
|
109
|
+
X_forecast, Z_forecast = dfm.predict(horizon=12)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Alternative: Direct Class Usage
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
from dfm_python import DFM, DFMConfig, SeriesConfig, BlockConfig
|
|
116
|
+
|
|
117
|
+
# Create config
|
|
118
|
+
config = DFMConfig(
|
|
119
|
+
series=[SeriesConfig(frequency='m', transformation='lin', blocks=[1], series_id='s1')],
|
|
120
|
+
blocks={'Block_Global': BlockConfig(factors=1, clock='m')}
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
# Fit model
|
|
124
|
+
model = DFM()
|
|
125
|
+
result = model.fit(X, config, max_iter=100)
|
|
126
|
+
factors = result.Z
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## Configuration
|
|
130
|
+
|
|
131
|
+
### Spec CSV + Params (Recommended for CSV workflows)
|
|
132
|
+
|
|
133
|
+
```python
|
|
134
|
+
from dfm_python.config import Params
|
|
135
|
+
|
|
136
|
+
params = Params(
|
|
137
|
+
max_iter=5000,
|
|
138
|
+
threshold=1e-5,
|
|
139
|
+
regularization_scale=1e-5,
|
|
140
|
+
damping_factor=0.8
|
|
141
|
+
)
|
|
142
|
+
dfm.from_spec('data/sample_spec.csv', params=params)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Hydra Decorator (Recommended for Hydra users)
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
import hydra
|
|
149
|
+
from hydra.utils import get_original_cwd
|
|
150
|
+
from omegaconf import DictConfig
|
|
151
|
+
import dfm_python as dfm
|
|
152
|
+
|
|
153
|
+
@hydra.main(config_path="../config", config_name="default", version_base="1.3")
|
|
154
|
+
def main(cfg: DictConfig) -> None:
|
|
155
|
+
dfm.load_config(hydra=cfg)
|
|
156
|
+
dfm.load_data(str(get_original_cwd() / "data" / "sample_data.csv"))
|
|
157
|
+
dfm.train(max_iter=cfg.max_iter)
|
|
158
|
+
X_forecast, Z_forecast = dfm.predict(horizon=cfg.get('forecast_horizon', 12))
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**CLI Overrides**: `python script.py max_iter=10 threshold=1e-4 blocks.Block_Global.factors=2`
|
|
162
|
+
|
|
163
|
+
### Dictionary
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
config_dict = {
|
|
167
|
+
'clock': 'm',
|
|
168
|
+
'max_iter': 5000,
|
|
169
|
+
'blocks': {'Block_Global': {'factors': 1, 'clock': 'm'}},
|
|
170
|
+
'series': [{'series_id': 's1', 'frequency': 'm', 'transformation': 'lin', 'blocks': [0]}]
|
|
171
|
+
}
|
|
172
|
+
dfm.from_dict(config_dict)
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Key Parameters
|
|
176
|
+
|
|
177
|
+
- **clock**: Base frequency for latent factors (typically "m" for monthly)
|
|
178
|
+
- **threshold**: EM convergence criterion (default: 1e-5)
|
|
179
|
+
- **max_iter**: Maximum EM iterations (default: 5000)
|
|
180
|
+
- **ar_lag**: Autoregressive lag for factors (default: 1)
|
|
181
|
+
- **regularization_scale**: Scale factor for ridge regularization (default: 1e-5)
|
|
182
|
+
- **damping_factor**: Damping factor for parameter updates (default: 0.8)
|
|
183
|
+
|
|
184
|
+
All numerical stability parameters are configurable and transparent. See `Params` dataclass for full list.
|
|
185
|
+
|
|
186
|
+
## Data Format
|
|
187
|
+
|
|
188
|
+
CSV file with series as columns and dates as rows:
|
|
189
|
+
|
|
190
|
+
```csv
|
|
191
|
+
Date,gdp_real,consumption,investment
|
|
192
|
+
2000-01-01,,98.5,95.0
|
|
193
|
+
2000-02-01,,98.7,95.2
|
|
194
|
+
2000-03-01,100.5,99.0,95.5
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
**Requirements**:
|
|
198
|
+
- First column: `Date` (YYYY-MM-DD format)
|
|
199
|
+
- Column names: Must match `series_id` in configuration
|
|
200
|
+
- Missing values: Empty cells or NaN
|
|
201
|
+
- Mixed frequencies: Quarterly series only at quarter-end months
|
|
202
|
+
|
|
203
|
+
**Frequency Support**: Monthly (m), Quarterly (q), Semi-annual (sa), Annual (a)
|
|
204
|
+
|
|
205
|
+
## News Decomposition
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from dfm_python import news_dfm
|
|
209
|
+
|
|
210
|
+
# Decompose forecast updates
|
|
211
|
+
y_old, y_new, singlenews, actual, forecast, weight, t_miss, v_miss, innov = news_dfm(
|
|
212
|
+
X_old, result_old, t_fcst=100, v_news=0
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
# Forecast update
|
|
216
|
+
forecast_update = y_new - y_old
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
## API Reference
|
|
220
|
+
|
|
221
|
+
### Module-Level Functions
|
|
222
|
+
|
|
223
|
+
- `dfm.from_spec(spec_path, params=None)` - Load from spec CSV + Params
|
|
224
|
+
- `dfm.from_yaml(yaml_path)` - Load from YAML file
|
|
225
|
+
- `dfm.from_dict(config_dict)` - Load from dictionary
|
|
226
|
+
- `dfm.load_data(data_path, sample_start=None, sample_end=None)` - Load data
|
|
227
|
+
- `dfm.train(max_iter=None, threshold=None, **kwargs)` - Train model
|
|
228
|
+
- `dfm.predict(horizon=12)` - Forecast series and factors
|
|
229
|
+
- `dfm.plot(kind='factor', factor_index=0, forecast_horizon=None, save_path=None)` - Plot results
|
|
230
|
+
- `dfm.get_result()` - Get `DFMResult` object
|
|
231
|
+
|
|
232
|
+
### DFMResult Object
|
|
233
|
+
|
|
234
|
+
Contains all estimation outputs:
|
|
235
|
+
- **Factors**: `Z` (T × m), `C` (N × m)
|
|
236
|
+
- **Parameters**: `A` (m × m), `Q` (m × m), `R` (N × N)
|
|
237
|
+
- **Smoothed Data**: `X_sm` (T × N), `x_sm` (T × N)
|
|
238
|
+
- **Convergence**: `converged`, `num_iter`, `loglik`
|
|
239
|
+
- **Model Fit**: `rmse`, `rmse_per_series`
|
|
240
|
+
|
|
241
|
+
## Architecture
|
|
242
|
+
|
|
243
|
+
**Core Modules**:
|
|
244
|
+
- `config.py`: Configuration management (DFMConfig, SeriesConfig, BlockConfig, Params)
|
|
245
|
+
- `dfm.py`: Core estimation (DFM class with fit() method)
|
|
246
|
+
- `api.py`: High-level convenience API
|
|
247
|
+
- `kalman.py`: Kalman filter and smoother
|
|
248
|
+
- `news.py`: News decomposition
|
|
249
|
+
|
|
250
|
+
**Core Submodules**:
|
|
251
|
+
- `core/em.py`: EM algorithm core
|
|
252
|
+
- `core/numeric.py`: Numerical utilities
|
|
253
|
+
- `core/diagnostics.py`: Diagnostic functions
|
|
254
|
+
- `core/results.py`: Result metrics
|
|
255
|
+
- `core/grouping.py`: Frequency grouping utilities
|
|
256
|
+
|
|
257
|
+
## Testing
|
|
258
|
+
|
|
259
|
+
```bash
|
|
260
|
+
pytest src/test/ -v
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Tests are organized into 5 files:
|
|
264
|
+
- `test_dfm.py` - Core DFM estimation
|
|
265
|
+
- `test_kalman.py` - Kalman filter/smoother
|
|
266
|
+
- `test_news.py` - News decomposition
|
|
267
|
+
- `test_config.py` - Configuration and API
|
|
268
|
+
- `test_api.py` - Edge cases and tutorials
|
|
269
|
+
|
|
270
|
+
## Tutorials
|
|
271
|
+
|
|
272
|
+
1. **`tutorial/basic_tutorial.py`** - Spec CSV + Params approach
|
|
273
|
+
```bash
|
|
274
|
+
python tutorial/basic_tutorial.py --spec data/sample_spec.csv --data data/sample_data.csv
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
2. **`tutorial/hydra_tutorial.py`** - Hydra decorator approach
|
|
278
|
+
```bash
|
|
279
|
+
python tutorial/hydra_tutorial.py max_iter=10 threshold=1e-4
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Troubleshooting
|
|
283
|
+
|
|
284
|
+
**Convergence Issues**: Increase `max_iter`, relax `threshold`, check data quality
|
|
285
|
+
|
|
286
|
+
**Dimension Mismatch**: Ensure `series_id` matches data column names, verify block structure
|
|
287
|
+
|
|
288
|
+
**Numerical Instability**: Monitor warnings, adjust thresholds, investigate data quality
|
|
289
|
+
|
|
290
|
+
## License
|
|
291
|
+
|
|
292
|
+
MIT License
|
|
293
|
+
|
|
294
|
+
## Citation
|
|
295
|
+
|
|
296
|
+
```bibtex
|
|
297
|
+
@software{dfm-python,
|
|
298
|
+
title = {dfm-python: Dynamic Factor Models for Nowcasting and Forecasting},
|
|
299
|
+
author = {DFM Python Contributors},
|
|
300
|
+
year = {2025},
|
|
301
|
+
url = {https://pypi.org/project/dfm-python/}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
**Package Status**: Stable (v0.2.1)
|
|
308
|
+
**PyPI**: https://pypi.org/project/dfm-python/
|
|
309
|
+
**Python**: 3.12+
|
|
310
|
+
**Latest Changes**: See [CHANGELOG.md](CHANGELOG.md)
|