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.
Files changed (48) hide show
  1. dfm_python-0.2.1/CHANGELOG.md +216 -0
  2. dfm_python-0.2.1/PKG-INFO +310 -0
  3. dfm_python-0.2.1/README.md +266 -0
  4. {dfm_python-0.2.0 → dfm_python-0.2.1}/pyproject.toml +1 -1
  5. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/__init__.py +2 -2
  6. dfm_python-0.2.0/src/dfm_python/dfm_api.py → dfm_python-0.2.1/src/dfm_python/api.py +41 -251
  7. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/config.py +72 -7
  8. dfm_python-0.2.1/src/dfm_python/core/__init__.py +59 -0
  9. dfm_python-0.2.1/src/dfm_python/core/diagnostics.py +274 -0
  10. dfm_python-0.2.1/src/dfm_python/core/em.py +1022 -0
  11. dfm_python-0.2.1/src/dfm_python/core/grouping.py +54 -0
  12. dfm_python-0.2.1/src/dfm_python/core/helpers.py +56 -0
  13. dfm_python-0.2.1/src/dfm_python/core/numeric.py +346 -0
  14. dfm_python-0.2.1/src/dfm_python/core/results.py +70 -0
  15. dfm_python-0.2.1/src/dfm_python/dfm.py +877 -0
  16. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/kalman.py +18 -0
  17. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/data_utils.py +3 -5
  18. dfm_python-0.2.1/src/test/test_api.py +251 -0
  19. dfm_python-0.2.1/src/test/test_config.py +296 -0
  20. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_dfm.py +19 -5
  21. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_news.py +2 -1
  22. {dfm_python-0.2.0 → dfm_python-0.2.1}/tutorial/basic_tutorial.py +4 -4
  23. {dfm_python-0.2.0 → dfm_python-0.2.1}/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.1}/.gitignore +0 -0
  33. {dfm_python-0.2.0 → dfm_python-0.2.1}/.python-version +0 -0
  34. {dfm_python-0.2.0 → dfm_python-0.2.1}/LICENSE +0 -0
  35. {dfm_python-0.2.0 → dfm_python-0.2.1}/MANIFEST.in +0 -0
  36. {dfm_python-0.2.0 → dfm_python-0.2.1}/config/blocks/default.yaml +0 -0
  37. {dfm_python-0.2.0 → dfm_python-0.2.1}/config/default.yaml +0 -0
  38. {dfm_python-0.2.0 → dfm_python-0.2.1}/config/series/default.yaml +0 -0
  39. {dfm_python-0.2.0 → dfm_python-0.2.1}/data/sample_data.csv +0 -0
  40. {dfm_python-0.2.0 → dfm_python-0.2.1}/data/sample_spec.csv +0 -0
  41. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/__init__.py +0 -0
  42. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/data_loader.py +0 -0
  43. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/news.py +0 -0
  44. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/__init__.py +0 -0
  45. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/dfm_python/utils/aggregation.py +0 -0
  46. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/__init__.py +0 -0
  47. {dfm_python-0.2.0 → dfm_python-0.2.1}/src/test/test_kalman.py +0 -0
  48. {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
+ [![PyPI version](https://img.shields.io/pypi/v/dfm-python.svg)](https://pypi.org/project/dfm-python/)
48
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](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)