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