dfm-python 0.1.4__tar.gz → 0.1.6__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 (35) hide show
  1. {dfm_python-0.1.4 → dfm_python-0.1.6}/.gitignore +2 -0
  2. dfm_python-0.1.6/PKG-INFO +572 -0
  3. dfm_python-0.1.6/README.md +530 -0
  4. dfm_python-0.1.6/config/example_config_macro_data.yaml +214 -0
  5. dfm_python-0.1.6/data/example_macro_data.csv +18 -0
  6. {dfm_python-0.1.4 → dfm_python-0.1.6}/pyproject.toml +1 -1
  7. dfm_python-0.1.6/scripts/inference.py +226 -0
  8. dfm_python-0.1.6/scripts/train.py +282 -0
  9. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/__init__.py +3 -3
  10. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/config.py +79 -5
  11. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/data_loader.py +94 -3
  12. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/dfm.py +1273 -275
  13. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/news.py +11 -1
  14. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/test/test_dfm.py +3 -357
  15. dfm_python-0.1.4/BUG_ANALYSIS.md +0 -242
  16. dfm_python-0.1.4/PKG-INFO +0 -1010
  17. dfm_python-0.1.4/README.md +0 -968
  18. dfm_python-0.1.4/test_comprehensive.py +0 -510
  19. {dfm_python-0.1.4 → dfm_python-0.1.6}/.python-version +0 -0
  20. {dfm_python-0.1.4 → dfm_python-0.1.6}/CHANGELOG.md +0 -0
  21. {dfm_python-0.1.4 → dfm_python-0.1.6}/LICENSE +0 -0
  22. {dfm_python-0.1.4 → dfm_python-0.1.6}/MANIFEST.in +0 -0
  23. {dfm_python-0.1.4 → dfm_python-0.1.6}/config/example_config.yaml +0 -0
  24. {dfm_python-0.1.4 → dfm_python-0.1.6}/data/sample_data.csv +0 -0
  25. {dfm_python-0.1.4 → dfm_python-0.1.6}/spec/example_spec.csv +0 -0
  26. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/__init__.py +0 -0
  27. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/kalman.py +0 -0
  28. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/utils/__init__.py +0 -0
  29. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/utils/aggregation.py +0 -0
  30. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/dfm_python/utils/data_utils.py +0 -0
  31. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/test/__init__.py +0 -0
  32. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/test/test_kalman.py +0 -0
  33. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/test/test_news.py +0 -0
  34. {dfm_python-0.1.4 → dfm_python-0.1.6}/src/test/test_synthetic.py +0 -0
  35. {dfm_python-0.1.4 → dfm_python-0.1.6}/uv.lock +0 -0
@@ -6,6 +6,8 @@ __pycache__/
6
6
  # C extensions
7
7
  *.so
8
8
 
9
+ outputs/
10
+
9
11
  # Distribution / packaging
10
12
  .Python
11
13
  build/
@@ -0,0 +1,572 @@
1
+ Metadata-Version: 2.4
2
+ Name: dfm-python
3
+ Version: 0.1.6
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: numpy>=1.24.0
21
+ Requires-Dist: pandas>=2.0.0
22
+ Requires-Dist: scipy>=1.10.0
23
+ Provides-Extra: all
24
+ Requires-Dist: httpx>=0.24.0; extra == 'all'
25
+ Requires-Dist: hydra-core>=1.3.0; extra == 'all'
26
+ Requires-Dist: omegaconf>=2.3.0; extra == 'all'
27
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == 'all'
28
+ Requires-Dist: pydantic-settings>=2.11.0; extra == 'all'
29
+ Requires-Dist: pytest>=7.0.0; extra == 'all'
30
+ Requires-Dist: supabase>=2.0.0; extra == 'all'
31
+ Provides-Extra: database
32
+ Requires-Dist: httpx>=0.24.0; extra == 'database'
33
+ Requires-Dist: psycopg2-binary>=2.9.0; extra == 'database'
34
+ Requires-Dist: pydantic-settings>=2.11.0; extra == 'database'
35
+ Requires-Dist: supabase>=2.0.0; extra == 'database'
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest>=7.0.0; extra == 'dev'
38
+ Provides-Extra: hydra
39
+ Requires-Dist: hydra-core>=1.3.0; extra == 'hydra'
40
+ Requires-Dist: omegaconf>=2.3.0; extra == 'hydra'
41
+ Description-Content-Type: text/markdown
42
+
43
+ # dfm-python: Dynamic Factor Models for Python
44
+
45
+ [![PyPI version](https://img.shields.io/pypi/v/dfm-python.svg)](https://pypi.org/project/dfm-python/)
46
+ [![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
47
+
48
+ A comprehensive Python implementation of **Dynamic Factor Models (DFM)** for nowcasting and forecasting high-dimensional time series. This package implements the FRBNY (Federal Reserve Bank of New York) approach with clock-based synchronization and tent kernel aggregation for mixed-frequency data.
49
+
50
+ ## Table of Contents
51
+
52
+ - [Overview](#overview)
53
+ - [Dynamic Factor Model Theory](#dynamic-factor-model-theory)
54
+ - [Core Features](#core-features)
55
+ - [Installation](#installation)
56
+ - [Quick Start](#quick-start)
57
+ - [Configuration](#configuration)
58
+ - [Data Format](#data-format)
59
+ - [Usage Examples](#usage-examples)
60
+ - [API Reference](#api-reference)
61
+ - [Advanced Features](#advanced-features)
62
+ - [Troubleshooting](#troubleshooting)
63
+ - [Architecture](#architecture)
64
+ - [License](#license)
65
+
66
+ ## Overview
67
+
68
+ Dynamic Factor Models extract common latent factors from multiple observed time series, enabling:
69
+ - **Nowcasting**: Real-time forecasting of current economic conditions using partial information
70
+ - **Forecasting**: Multi-step ahead predictions of key economic indicators
71
+ - **Factor Analysis**: Identification of common trends driving multiple series
72
+ - **News Decomposition**: Attribution of forecast changes to individual data releases
73
+
74
+ The model handles high-dimensional datasets (dozens to hundreds of series) with mixed frequencies (daily, weekly, monthly, quarterly) and robustly manages missing data.
75
+
76
+ ## Dynamic Factor Model Theory
77
+
78
+ ### Mathematical Framework
79
+
80
+ A Dynamic Factor Model represents observed time series as:
81
+
82
+ ```
83
+ y_t = C × Z_t + e_t (Observation equation)
84
+ Z_t = A × Z_{t-1} + v_t (State equation)
85
+ ```
86
+
87
+ Where:
88
+ - **y_t**: n × 1 vector of observed series at time t
89
+ - **Z_t**: m × 1 vector of unobserved common factors
90
+ - **C**: n × m factor loading matrix (how series relate to factors)
91
+ - **A**: m × m transition matrix (how factors evolve over time)
92
+ - **e_t**: n × 1 observation errors ~ N(0, R)
93
+ - **v_t**: m × 1 state innovations ~ N(0, Q)
94
+
95
+ ### State-Space Representation
96
+
97
+ The DFM is a state-space model where:
98
+ - **State**: Latent factors Z_t evolve according to a VAR(p) process
99
+ - **Observation**: Observed series y_t are linear combinations of factors plus noise
100
+ - **Estimation**: Parameters (C, A, Q, R) estimated via Expectation-Maximization (EM) algorithm
101
+
102
+ ### Expectation-Maximization Algorithm
103
+
104
+ The EM algorithm iteratively:
105
+ 1. **E-step**: Run Kalman filter/smoother to estimate factors Z_t given current parameters
106
+ 2. **M-step**: Update parameters (C, A, Q, R) to maximize likelihood given estimated factors
107
+ 3. **Convergence**: Iterate until log-likelihood change falls below threshold
108
+
109
+ This yields maximum likelihood estimates of all parameters and smoothed factor estimates.
110
+
111
+ ### Block Structure
112
+
113
+ Factors are organized into blocks representing different economic domains:
114
+ - **Global factors**: Common to all series (e.g., business cycle)
115
+ - **Sector factors**: Specific to groups of series (e.g., consumption, investment)
116
+ - **Idiosyncratic components**: Series-specific dynamics
117
+
118
+ Each series loads on one or more blocks, allowing flexible factor structures.
119
+
120
+ ### Mixed-Frequency Framework
121
+
122
+ The package implements a **clock-based** approach where:
123
+ - All latent factors evolve at a common "clock" frequency (typically monthly)
124
+ - Lower-frequency observations (e.g., quarterly) map to higher-frequency states via deterministic tent kernels
125
+ - Higher-frequency observations (e.g., daily) handled via missing data approach
126
+
127
+ **Tent Kernels**: For quarterly-to-monthly mapping, quarterly observations connect to 5 monthly latent states with weights [1, 2, 3, 2, 1], peaking at the middle month. This ensures quarterly aggregates equal weighted sums of monthly states.
128
+
129
+ ## Core Features
130
+
131
+ ### Mixed-Frequency Data Handling
132
+
133
+ Seamlessly combine series with different reporting frequencies:
134
+ - **Daily** (d): High-frequency financial data
135
+ - **Weekly** (w): Weekly indicators
136
+ - **Monthly** (m): Standard economic indicators
137
+ - **Quarterly** (q): National accounts, GDP
138
+ - **Semi-annual** (sa): Semi-annual aggregates
139
+ - **Annual** (a): Annual aggregates
140
+
141
+ The model automatically handles frequency conversion using tent kernels for lower frequencies and missing data interpolation for higher frequencies.
142
+
143
+ ### Robust Missing Data
144
+
145
+ Missing observations are handled via:
146
+ - Spline interpolation for gaps in time series
147
+ - Kalman filter naturally accounts for missing data in likelihood
148
+ - Tested with up to 50% missing data per series
149
+
150
+ ### Block Structure
151
+
152
+ Organize factors into logical groups:
153
+ - Global factors affecting all series
154
+ - Sector-specific factors (consumption, investment, external, etc.)
155
+ - Flexible loading structure: series can load on multiple blocks
156
+
157
+ ### Data Transformations
158
+
159
+ Support for standard econometric transformations:
160
+ - `lin`: Levels (no transformation)
161
+ - `chg`: First difference
162
+ - `pch`: Percent change
163
+ - `pca`: Percent change at annual rate
164
+ - `log`: Natural logarithm
165
+ - And more (ch1, pc1, cch, cca)
166
+
167
+ Transformations ensure stationarity and proper scaling of series.
168
+
169
+ ### News Decomposition
170
+
171
+ Decompose forecast updates into contributions from individual data releases:
172
+ - Identify which new data points drive forecast changes
173
+ - Quantify impact of each data release
174
+ - Essential for understanding nowcast revisions
175
+
176
+ ## Installation
177
+
178
+ ```bash
179
+ pip install dfm-python
180
+ ```
181
+
182
+ ### Requirements
183
+
184
+ - Python >= 3.12
185
+ - numpy >= 1.24.0
186
+ - pandas >= 2.0.0
187
+ - scipy >= 1.10.0
188
+
189
+ ## Quick Start
190
+
191
+ ```python
192
+ from dfm_python import load_config, load_data, dfm
193
+
194
+ # Load configuration and data
195
+ config = load_config('config/example_config.yaml')
196
+ X, Time, mnemonics = load_data('data/example_data.csv', config)
197
+
198
+ # Estimate model
199
+ result = dfm(X, config, threshold=1e-5, max_iter=5000)
200
+
201
+ # Access results
202
+ factors = result.Z # Smoothed factors (T × m)
203
+ loadings = result.C # Factor loadings (N × m)
204
+ smoothed = result.X_sm # Smoothed data (T × N)
205
+ rmse = result.rmse # Model fit (RMSE)
206
+ ```
207
+
208
+ ## Configuration
209
+
210
+ ### YAML Format
211
+
212
+ ```yaml
213
+ # DFM estimation parameters
214
+ dfm:
215
+ clock: "m" # Base frequency for latent factors
216
+ threshold: 1e-5 # EM convergence threshold
217
+ max_iter: 5000 # Maximum EM iterations
218
+ ar_lag: 1 # AR lag for factors
219
+
220
+ # Model structure
221
+ model:
222
+ blocks:
223
+ Global:
224
+ factors: 3 # Number of factors in block
225
+ Consumption:
226
+ factors: 2
227
+ Investment:
228
+ factors: 2
229
+
230
+ # Series definitions
231
+ series:
232
+ gdp_real:
233
+ series_name: "Real GDP (Quarterly)"
234
+ frequency: "q"
235
+ transformation: "pca"
236
+ units: "Index"
237
+ blocks: [Global]
238
+
239
+ consumption:
240
+ series_name: "Consumption (Monthly)"
241
+ frequency: "m"
242
+ transformation: "pch"
243
+ units: "Index"
244
+ blocks: [Global, Consumption]
245
+ ```
246
+
247
+ ### Key Parameters
248
+
249
+ - **clock**: Base frequency for all latent factors (typically "m" for monthly)
250
+ - **threshold**: Convergence criterion for EM algorithm (smaller = more precise)
251
+ - **max_iter**: Maximum EM iterations (typically 100-5000)
252
+ - **ar_lag**: Autoregressive lag for factors (typically 1 for AR(1))
253
+
254
+ ### Numerical Stability Parameters
255
+
256
+ For reproducibility and transparency, all numerical stability techniques are configurable:
257
+
258
+ ```yaml
259
+ dfm:
260
+ # AR Coefficient Clipping
261
+ clip_ar_coefficients: true # Enable AR coefficient clipping for stationarity
262
+ ar_clip_min: -0.99 # Minimum AR coefficient (must be > -1)
263
+ ar_clip_max: 0.99 # Maximum AR coefficient (must be < 1)
264
+ warn_on_ar_clip: true # Warn when clipping occurs
265
+
266
+ # Data Value Clipping
267
+ clip_data_values: true # Enable clipping of extreme data values
268
+ data_clip_threshold: 100.0 # Clip values beyond this many standard deviations
269
+ warn_on_data_clip: true # Warn when clipping occurs
270
+
271
+ # Regularization
272
+ use_regularization: true # Enable regularization for numerical stability
273
+ regularization_scale: 1e-6 # Scale factor for ridge regularization
274
+ min_eigenvalue: 1e-8 # Minimum eigenvalue for positive definite matrices
275
+ max_eigenvalue: 1e6 # Maximum eigenvalue cap
276
+ warn_on_regularization: true # Warn when regularization is applied
277
+
278
+ # Damped Updates
279
+ use_damped_updates: true # Enable damped updates when likelihood decreases
280
+ damping_factor: 0.8 # Damping factor (0.8 = 80% new, 20% old)
281
+ warn_on_damped_update: true # Warn when damped updates are used
282
+ ```
283
+
284
+ **Important**: These parameters are fully transparent and documented. When enabled, the package logs warnings explaining when and why each technique is applied, allowing researchers to understand any potential bias introduced. All parameters can be disabled or adjusted for research purposes.
285
+
286
+ ## Data Format
287
+
288
+ ### CSV Structure
289
+
290
+ Data file should be CSV with series as columns and dates as rows:
291
+
292
+ ```csv
293
+ Date,gdp_real,consumption,investment
294
+ 2000-01-01,,98.5,95.0
295
+ 2000-02-01,,98.7,95.2
296
+ 2000-03-01,100.5,99.0,95.5
297
+ 2000-04-01,,99.3,95.8
298
+ ```
299
+
300
+ **Requirements**:
301
+ - First column: `Date` (YYYY-MM-DD format)
302
+ - Column names: Must match `series_id` in configuration
303
+ - Missing values: Use empty cells or NaN
304
+ - Mixed frequencies: Quarterly series only have values at quarter-end months (Mar, Jun, Sep, Dec)
305
+
306
+ ## Usage Examples
307
+
308
+ ### Basic Estimation
309
+
310
+ ```python
311
+ from dfm_python import load_config, load_data, dfm
312
+
313
+ # Load configuration and data
314
+ config = load_config('config/example_config.yaml')
315
+ X, Time, mnemonics = load_data('data/example_data.csv', config)
316
+
317
+ # Estimate model
318
+ result = dfm(X, config, threshold=1e-5, max_iter=5000)
319
+
320
+ # Extract common factor (first factor)
321
+ common_factor = result.Z[:, 0]
322
+
323
+ # Reconstruct series from factors
324
+ series_reconstructed = result.Z @ result.C[0, :].T
325
+ ```
326
+
327
+ ### Working with Results
328
+
329
+ ```python
330
+ # Access all components
331
+ factors = result.Z # (T × m) Factor estimates
332
+ loadings = result.C # (N × m) Factor loadings
333
+ transition = result.A # (m × m) Transition matrix
334
+ covariance = result.Q # (m × m) Factor covariance
335
+ smoothed_data = result.X_sm # (T × N) Smoothed data
336
+
337
+ # Model fit statistics
338
+ overall_rmse = result.rmse
339
+ rmse_per_series = result.rmse_per_series
340
+
341
+ # Convergence info
342
+ converged = result.converged
343
+ iterations = result.num_iter
344
+ loglikelihood = result.loglik
345
+ ```
346
+
347
+ ### News Decomposition
348
+
349
+ ```python
350
+ from dfm_python import news_dfm
351
+
352
+ # Estimate on old and new data
353
+ result_old = dfm(X_old, config)
354
+ result_new = dfm(X_new, config)
355
+
356
+ # Decompose news
357
+ y_old, y_new, singlenews, actual, forecast, weight, t_miss, v_miss, innov = news_dfm(
358
+ X_old, # Old vintage data
359
+ X_new, # New vintage data
360
+ result_old, # DFM results
361
+ t_fcst=100, # Forecast time index
362
+ v_news=0 # Target variable index
363
+ )
364
+
365
+ # Forecast update
366
+ forecast_update = y_new - y_old
367
+
368
+ # News contributions from each series
369
+ for i, contribution in enumerate(singlenews):
370
+ if not np.isnan(contribution):
371
+ print(f"Series {i}: {contribution:.4f}")
372
+ ```
373
+
374
+ ## API Reference
375
+
376
+ ### Main Functions
377
+
378
+ #### `load_config(file: str) -> DFMConfig`
379
+
380
+ Load configuration from YAML file.
381
+
382
+ **Parameters**:
383
+ - `file`: Path to YAML configuration file
384
+
385
+ **Returns**: `DFMConfig` object
386
+
387
+ #### `load_data(file: str, config: DFMConfig) -> Tuple[np.ndarray, pd.DatetimeIndex, List[str]]`
388
+
389
+ Load and transform data from CSV file.
390
+
391
+ **Parameters**:
392
+ - `file`: Path to CSV data file
393
+ - `config`: DFM configuration object
394
+
395
+ **Returns**:
396
+ - `X`: Transformed data matrix (T × N)
397
+ - `Time`: Time index (DatetimeIndex)
398
+ - `mnemonics`: List of series IDs
399
+
400
+ #### `dfm(X: np.ndarray, config: DFMConfig, threshold: float = None, max_iter: int = None) -> DFMResult`
401
+
402
+ Estimate Dynamic Factor Model using EM algorithm.
403
+
404
+ **Parameters**:
405
+ - `X`: Data matrix (T × N) with possible missing values
406
+ - `config`: DFM configuration object
407
+ - `threshold`: Convergence threshold (default: from config)
408
+ - `max_iter`: Maximum EM iterations (default: from config)
409
+
410
+ **Returns**: `DFMResult` object containing all estimation outputs
411
+
412
+ ### Result Object
413
+
414
+ #### `DFMResult`
415
+
416
+ Dataclass containing all estimation outputs:
417
+
418
+ **Factor Estimates**:
419
+ - `Z`: Smoothed factors (T × m)
420
+ - `C`: Factor loadings (N × m)
421
+
422
+ **Model Parameters**:
423
+ - `A`: Transition matrix (m × m)
424
+ - `Q`: Factor covariance (m × m)
425
+ - `R`: Observation covariance (N × N)
426
+
427
+ **Smoothed Data**:
428
+ - `X_sm`: Unstandardized smoothed data (T × N)
429
+ - `x_sm`: Standardized smoothed data (T × N)
430
+
431
+ **Initial Conditions**:
432
+ - `Z_0`: Initial state (m,)
433
+ - `V_0`: Initial covariance (m × m)
434
+
435
+ **Standardization**:
436
+ - `Mx`: Series means (N,)
437
+ - `Wx`: Series standard deviations (N,)
438
+
439
+ **Model Structure**:
440
+ - `r`: Factors per block (n_blocks,)
441
+ - `p`: AR lag
442
+
443
+ **Convergence Info**:
444
+ - `converged`: Whether EM converged
445
+ - `num_iter`: Number of iterations
446
+ - `loglik`: Final log-likelihood
447
+
448
+ **Model Fit**:
449
+ - `rmse`: Overall RMSE
450
+ - `rmse_per_series`: RMSE per series (N,)
451
+
452
+ ## Advanced Features
453
+
454
+ ### Clock-Based Mixed-Frequency Framework
455
+
456
+ All latent factors evolve at a common clock frequency (typically monthly). Lower-frequency observations map to higher-frequency states via deterministic tent kernels:
457
+
458
+ - **Quarterly → Monthly**: 5-period tent with weights [1, 2, 3, 2, 1]
459
+ - **Semi-annual → Monthly**: 7-period tent
460
+ - **Annual → Monthly**: 9-period tent
461
+ - **Maximum tent size**: 12 periods (larger gaps use missing data approach)
462
+
463
+ This ensures quarterly aggregates equal weighted sums of monthly latent states.
464
+
465
+ ### Kalman Filtering and Smoothing
466
+
467
+ The package uses standard Kalman filter for forward pass and fixed-interval smoother for backward pass:
468
+ - **Filter**: Computes filtered state estimates and covariances
469
+ - **Smoother**: Computes smoothed estimates using all available data
470
+ - **Missing data**: Handled naturally by Kalman filter
471
+
472
+ ### Block Structure and Factor Loading
473
+
474
+ Each series loads on one or more blocks:
475
+ - All series must load on first block (global factor)
476
+ - Series can load on multiple blocks simultaneously
477
+ - Each block can have multiple factors
478
+ - Loadings estimated via PCA (monthly) or constrained least squares (quarterly)
479
+
480
+ ### Idiosyncratic Components
481
+
482
+ Each series has an idiosyncratic component modeled as AR(1) process:
483
+ - Monthly series: Single AR(1) component
484
+ - Quarterly series: 5 AR(1) components (one per tent period) sharing same AR coefficient
485
+
486
+ ## Troubleshooting
487
+
488
+ ### Convergence Issues
489
+
490
+ If EM algorithm doesn't converge:
491
+ - Check data quality and missing data patterns
492
+ - Increase `max_iter` (try 10000)
493
+ - Relax `threshold` (try 1e-3 instead of 1e-5)
494
+ - Review initial conditions
495
+
496
+ ### Dimension Mismatch Errors
497
+
498
+ Ensure:
499
+ - `series_id` in config matches CSV column names exactly
500
+ - Block structure is consistent
501
+ - All series have valid frequency codes
502
+
503
+ ### Numerical Instability
504
+
505
+ The package includes comprehensive numerical stability features that are fully configurable:
506
+
507
+ **Automatic Stability Techniques**:
508
+ - **AR Coefficient Clipping**: Ensures stationarity by clipping AR coefficients to [-0.99, 0.99]
509
+ - **Data Value Clipping**: Clips extreme outliers beyond configurable threshold (default: 100 std devs)
510
+ - **Regularization**: Adds ridge regularization to prevent ill-conditioned matrices
511
+ - **Positive Definite Enforcement**: Ensures covariance matrices remain positive semi-definite
512
+ - **Damped Updates**: Prevents likelihood decreases by using weighted parameter updates
513
+
514
+ **Transparency**:
515
+ - All techniques are configurable via YAML config
516
+ - Warnings are logged when techniques are applied
517
+ - Statistics are tracked for monitoring
518
+ - Techniques can be disabled for research purposes
519
+
520
+ **Best Practices**:
521
+ - Monitor warnings to understand when stability techniques are applied
522
+ - If techniques are frequently needed, investigate data quality
523
+ - Adjust thresholds based on your data characteristics
524
+ - Consider disabling techniques if they introduce unacceptable bias
525
+
526
+ If issues persist, check data for outliers, extreme values, or near-unit root behavior.
527
+
528
+ ## Architecture
529
+
530
+ The package is modular and application-agnostic:
531
+
532
+ **Core Modules**:
533
+ - `config.py`: Configuration management
534
+ - `data_loader.py`: Data loading and transformation
535
+ - `dfm.py`: Core estimation (EM algorithm)
536
+ - `kalman.py`: Kalman filter and smoother
537
+ - `news.py`: News decomposition
538
+ - `utils/`: Utility functions (aggregation, data preprocessing)
539
+
540
+ **Design Principles**:
541
+ - Generic core (no application-specific code)
542
+ - Robust error handling
543
+ - Comprehensive numerical stability
544
+ - Clean, maintainable code structure
545
+
546
+ ## License
547
+
548
+ MIT License - see LICENSE file for details.
549
+
550
+ ## Citation
551
+
552
+ If you use this package in your research, please cite:
553
+
554
+ ```bibtex
555
+ @software{dfm-python,
556
+ title = {dfm-python: Dynamic Factor Models for Nowcasting and Forecasting},
557
+ author = {DFM Python Contributors},
558
+ year = {2025},
559
+ url = {https://pypi.org/project/dfm-python/},
560
+ version = {0.1.5}
561
+ }
562
+ ```
563
+
564
+ ## Acknowledgments
565
+
566
+ This package implements Dynamic Factor Models following established econometric methodology, with a focus on practical nowcasting and forecasting applications. The clock-based mixed-frequency framework follows the FRBNY (Federal Reserve Bank of New York) approach.
567
+
568
+ ---
569
+
570
+ **Package Status**: Stable (v0.1.5+)
571
+ **PyPI**: https://pypi.org/project/dfm-python/
572
+ **Python**: 3.12+