dfm-python 0.5.58__tar.gz → 0.5.60__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dfm_python-0.5.60/.cursor/agents/test-runner.md +118 -0
- dfm_python-0.5.60/=0.11.0 +1 -0
- dfm_python-0.5.60/PKG-INFO +56 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/config/ddfm_exchange.yaml +1 -1
- {dfm_python-0.5.58 → dfm_python-0.5.60}/config/ddfm_finance.yaml +1 -1
- {dfm_python-0.5.58 → dfm_python-0.5.60}/config/ddfm_macro.yaml +1 -1
- dfm_python-0.5.60/config/dfm_exchange.yaml +32 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/config/dfm_finance.yaml +2 -5
- {dfm_python-0.5.58 → dfm_python-0.5.60}/config/dfm_macro.yaml +2 -5
- {dfm_python-0.5.58 → dfm_python-0.5.60}/pyproject.toml +2 -2
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/__init__.py +8 -3
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/__init__.py +2 -8
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/adapter.py +0 -1
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/schema/model.py +9 -8
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/schema/params.py +59 -89
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/dataset/ddfm_dataset.py +85 -47
- dfm_python-0.5.60/src/dfm_python/dataset/dfm_dataset.py +187 -0
- dfm_python-0.5.60/src/dfm_python/functional/em.py +1114 -0
- dfm_python-0.5.60/src/dfm_python/logger/dfm_logger.py +39 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/models/__init__.py +8 -4
- dfm_python-0.5.60/src/dfm_python/models/base.py +73 -0
- {dfm_python-0.5.58/src/dfm_python/models → dfm_python-0.5.60/src/dfm_python/models/ddfm}/ddfm.py +281 -54
- dfm_python-0.5.60/src/dfm_python/models/dfm/__init__.py +39 -0
- dfm_python-0.5.60/src/dfm_python/models/dfm/dfm.py +991 -0
- dfm_python-0.5.60/src/dfm_python/models/dfm/initialization.py +926 -0
- dfm_python-0.5.60/src/dfm_python/models/dfm/mixed_freq.py +262 -0
- {dfm_python-0.5.58/src/dfm_python/numeric → dfm_python-0.5.60/src/dfm_python/models/dfm}/tent.py +4 -5
- dfm_python-0.5.60/src/dfm_python/numeric/builder.py +197 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/numeric/estimator.py +1 -94
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/numeric/stability.py +6 -545
- dfm_python-0.5.60/src/dfm_python/numeric/validator.py +742 -0
- dfm_python-0.5.60/src/dfm_python/ssm/kalman.py +386 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/__init__.py +32 -56
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/misc.py +36 -13
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/validation.py +1 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/test_tent_weights_config.py +1 -1
- dfm_python-0.5.60/src/test/dataset/test_ddfm_dataset.py +0 -0
- dfm_python-0.5.60/src/test/dataset/test_dfm_dataset.py +0 -0
- dfm_python-0.5.60/src/test/functional/test_em.py +136 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/models/test_ddfm.py +26 -32
- dfm_python-0.5.60/src/test/models/test_dfm.py +92 -0
- dfm_python-0.5.60/src/test/numeric/test_builder.py +40 -0
- dfm_python-0.5.60/src/test/numeric/test_validator.py +122 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/ssm/test_kalman.py +5 -5
- {dfm_python-0.5.58 → dfm_python-0.5.60}/tutorial/tutorial_exchange_ddfm.py +12 -13
- dfm_python-0.5.60/tutorial/tutorial_exchange_dfm.py +68 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/tutorial/tutorial_finance_ddfm.py +6 -4
- dfm_python-0.5.60/tutorial/tutorial_finance_dfm.py +114 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/tutorial/tutorial_macro_ddfm.py +13 -5
- dfm_python-0.5.60/tutorial/tutorial_macro_dfm.py +119 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/uv.lock +28 -1
- dfm_python-0.5.58/PKG-INFO +0 -379
- dfm_python-0.5.58/README.md +0 -322
- dfm_python-0.5.58/src/dfm_python/dataset/dfm_dataset.py +0 -542
- dfm_python-0.5.58/src/dfm_python/functional/dfm_block.py +0 -485
- dfm_python-0.5.58/src/dfm_python/functional/em.py +0 -1356
- dfm_python-0.5.58/src/dfm_python/models/base.py +0 -292
- dfm_python-0.5.58/src/dfm_python/models/dfm.py +0 -1842
- dfm_python-0.5.58/src/dfm_python/numeric/builder.py +0 -187
- dfm_python-0.5.58/src/dfm_python/numeric/validator.py +0 -1110
- dfm_python-0.5.58/src/dfm_python/ssm/kalman.py +0 -628
- dfm_python-0.5.58/src/test/dataset/__init__.py +0 -2
- dfm_python-0.5.58/src/test/dataset/test_dataloader.py +0 -25
- dfm_python-0.5.58/src/test/dataset/test_dataset.py +0 -69
- dfm_python-0.5.58/src/test/dataset/test_process.py +0 -116
- dfm_python-0.5.58/src/test/functional/test_dfm_block.py +0 -140
- dfm_python-0.5.58/src/test/functional/test_em.py +0 -878
- dfm_python-0.5.58/src/test/models/test_base.py +0 -161
- dfm_python-0.5.58/src/test/models/test_ddfm_batchnorm_placement.py +0 -179
- dfm_python-0.5.58/src/test/models/test_dfm.py +0 -225
- dfm_python-0.5.58/src/test/models/test_dfm_fixes.py +0 -261
- dfm_python-0.5.58/src/test/models/test_dfm_result_caching.py +0 -309
- dfm_python-0.5.58/src/test/models/test_dfm_save_load.py +0 -261
- dfm_python-0.5.58/src/test/models/test_dfm_save_load_integration.py +0 -136
- dfm_python-0.5.58/src/test/models/test_dfm_save_load_mock.py +0 -340
- dfm_python-0.5.58/src/test/models/test_dfm_training_pipeline_save.py +0 -246
- dfm_python-0.5.58/src/test/models/test_tensorflow_batchnorm_comparison.py +0 -266
- dfm_python-0.5.58/src/test/numeric/test_builder.py +0 -27
- dfm_python-0.5.58/src/test/numeric/test_tent.py +0 -113
- dfm_python-0.5.58/src/test/numeric/test_validator.py +0 -279
- dfm_python-0.5.58/src/test/ssm/test_arma.py +0 -22
- dfm_python-0.5.58/src/test/ssm/test_companion.py +0 -103
- dfm_python-0.5.58/src/test/ssm/test_kalman_progress.py +0 -161
- dfm_python-0.5.58/src/test/ssm/test_progress_bar_exact_scenario.py +0 -226
- dfm_python-0.5.58/src/test/ssm/test_progress_bar_spam_fix.py +0 -297
- dfm_python-0.5.58/src/test/ssm/test_structural.py +0 -67
- dfm_python-0.5.58/src/test/utils/test_common.py +0 -458
- dfm_python-0.5.58/src/test/utils/test_tensor_utils.py +0 -57
- dfm_python-0.5.58/src/test/utils/test_validation.py +0 -137
- dfm_python-0.5.58/tutorial/tutorial_finance_dfm.py +0 -259
- dfm_python-0.5.58/tutorial/tutorial_illness_ddfm.py +0 -284
- dfm_python-0.5.58/tutorial/tutorial_macro_dfm.py +0 -306
- {dfm_python-0.5.58 → dfm_python-0.5.60}/.git +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/.gitignore +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/.python-version +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/MANIFEST.in +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/data/exchange_rate.csv +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/data/finance.csv +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/data/macro.csv +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/constants.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/schema/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/schema/block.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/schema/results.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/config/types.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/dataset/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/dataset/time.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/decoder/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/decoder/base.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/decoder/linear.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/decoder/mlp.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/encoder/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/encoder/base.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/encoder/pca.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/encoder/simple_autoencoder.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/functional/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/logger/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/logger/inference_logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/logger/logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/logger/train_logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/numeric/statistic.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/ssm/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/checkpoint.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/errors.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/helper.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/loss.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/dfm_python/utils/metric.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/schema/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/schema/test_block.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/schema/test_model.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/schema/test_results.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/test_adapter.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/test_constants.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/config/test_types.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/conftest.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/decoder/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/decoder/test_linear.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/decoder/test_mlp.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/encoder/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/encoder/test_base.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/encoder/test_pca.py +0 -0
- /dfm_python-0.5.58/src/test/encoder/test_simple_encoder.py → /dfm_python-0.5.60/src/test/encoder/test_simple_autoencoder.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/functional/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/logger/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/logger/test_inference_logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/logger/test_logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/logger/test_train_logger.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/models/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/numeric/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/numeric/test_estimator.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/numeric/test_stability.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/ssm/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/utils/__init__.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/utils/test_errors.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/utils/test_helper.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/utils/test_metric.py +0 -0
- {dfm_python-0.5.58 → dfm_python-0.5.60}/src/test/utils/test_misc.py +0 -0
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: test-runner
|
|
3
|
+
description: Testing specialist for running pytest, fixing test failures, and verifying implementations. Use proactively after code changes or when user requests testing.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
You are a testing specialist focused on running tests, diagnosing failures, and ensuring code correctness.
|
|
7
|
+
|
|
8
|
+
## Core Responsibilities
|
|
9
|
+
|
|
10
|
+
When invoked:
|
|
11
|
+
1. **Run tests** using `uv run pytest` (never use system pytest)
|
|
12
|
+
2. **Analyze failures** with clear error messages and stack traces
|
|
13
|
+
3. **Fix issues** directly in the code
|
|
14
|
+
4. **Verify fixes** by re-running tests
|
|
15
|
+
5. **Report results** concisely
|
|
16
|
+
|
|
17
|
+
## Testing Workflow
|
|
18
|
+
|
|
19
|
+
### 1. Environment Setup
|
|
20
|
+
- Always use `uv` and virtual environment (`.venv/`)
|
|
21
|
+
- Activate venv: `source .venv/bin/activate` OR use `uv run`
|
|
22
|
+
- Never use system `python` or `pytest` directly
|
|
23
|
+
|
|
24
|
+
### 2. Running Tests
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Run all tests
|
|
28
|
+
uv run pytest
|
|
29
|
+
|
|
30
|
+
# Run specific test file
|
|
31
|
+
uv run pytest src/test/models/test_dfm.py
|
|
32
|
+
|
|
33
|
+
# Run with verbose output
|
|
34
|
+
uv run pytest -v
|
|
35
|
+
|
|
36
|
+
# Run specific test function
|
|
37
|
+
uv run pytest src/test/models/test_dfm.py::TestDFM::test_dfm_fit
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### 3. Analyzing Failures
|
|
41
|
+
|
|
42
|
+
For each failure:
|
|
43
|
+
- **Read the error message** carefully
|
|
44
|
+
- **Check the stack trace** to locate the issue
|
|
45
|
+
- **Identify root cause** (not just symptoms)
|
|
46
|
+
- **Check recent code changes** if applicable
|
|
47
|
+
- **Verify imports and dependencies**
|
|
48
|
+
|
|
49
|
+
### 4. Fixing Issues
|
|
50
|
+
|
|
51
|
+
- **Fix directly** in the code (don't just report)
|
|
52
|
+
- **Make minimal changes** to resolve the issue
|
|
53
|
+
- **Preserve existing functionality** unless explicitly changing it
|
|
54
|
+
- **Update tests** if requirements changed (not just to make them pass)
|
|
55
|
+
|
|
56
|
+
### 5. Verification
|
|
57
|
+
|
|
58
|
+
- **Re-run the specific failing test** first
|
|
59
|
+
- **Run the full test suite** if multiple tests might be affected
|
|
60
|
+
- **Verify no regressions** introduced
|
|
61
|
+
|
|
62
|
+
## Common Issues and Fixes
|
|
63
|
+
|
|
64
|
+
### Import Errors
|
|
65
|
+
- Check if module exists and path is correct
|
|
66
|
+
- Verify `__init__.py` files exist
|
|
67
|
+
- Check if function/class was moved or renamed
|
|
68
|
+
- Update imports to match current code structure
|
|
69
|
+
|
|
70
|
+
### Assertion Failures
|
|
71
|
+
- Understand what the test expects vs what code produces
|
|
72
|
+
- Check if test expectations are outdated
|
|
73
|
+
- Verify logic correctness, not just make test pass
|
|
74
|
+
|
|
75
|
+
### Missing Dependencies
|
|
76
|
+
- Install with `uv pip install <package>`
|
|
77
|
+
- Check `pyproject.toml` for required dependencies
|
|
78
|
+
- Verify virtual environment has all packages
|
|
79
|
+
|
|
80
|
+
### Type Errors
|
|
81
|
+
- Check type hints match actual usage
|
|
82
|
+
- Verify imports for type annotations
|
|
83
|
+
- Update types if code behavior changed
|
|
84
|
+
|
|
85
|
+
## Output Format
|
|
86
|
+
|
|
87
|
+
After running tests, provide:
|
|
88
|
+
1. **Summary**: Total tests, passed, failed, skipped
|
|
89
|
+
2. **Failures**: List each failure with:
|
|
90
|
+
- Test name and location
|
|
91
|
+
- Error message
|
|
92
|
+
- Root cause analysis
|
|
93
|
+
- Fix applied
|
|
94
|
+
3. **Status**: All tests passing or remaining issues
|
|
95
|
+
|
|
96
|
+
## Best Practices
|
|
97
|
+
|
|
98
|
+
- **Run tests immediately** when requested
|
|
99
|
+
- **Fix issues proactively** - don't just report them
|
|
100
|
+
- **Use uv and venv** always
|
|
101
|
+
- **Be thorough** but efficient
|
|
102
|
+
- **Verify fixes** before reporting success
|
|
103
|
+
- **Keep test output** concise but informative
|
|
104
|
+
|
|
105
|
+
## Example Workflow
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
User: "Run tests for DFM"
|
|
109
|
+
Assistant:
|
|
110
|
+
1. Runs: `uv run pytest src/test/models/test_dfm.py -v`
|
|
111
|
+
2. Sees failure: ImportError for validate_dfm_initialization
|
|
112
|
+
3. Checks: Function exists in validator.py
|
|
113
|
+
4. Fixes: Updates import path in test file
|
|
114
|
+
5. Re-runs: `uv run pytest src/test/models/test_dfm.py::TestDFM::test_dfm_fit`
|
|
115
|
+
6. Reports: "Fixed import error. All DFM tests passing."
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Remember: Act quickly, fix directly, verify thoroughly.**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
Audited 1 package in 1ms
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dfm-python
|
|
3
|
+
Version: 0.5.60
|
|
4
|
+
Summary: Dynamic Factor Model (DFM) estimation and forecasting 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: Minkey Chang
|
|
10
|
+
License: MIT
|
|
11
|
+
Keywords: dfm,dynamic-factor-model,econometrics,forecasting,time-series
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Science/Research
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Topic :: Scientific/Engineering
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: build>=1.4.0
|
|
22
|
+
Requires-Dist: einops>=0.8.1
|
|
23
|
+
Requires-Dist: hydra-core>=1.3.2
|
|
24
|
+
Requires-Dist: matplotlib>=3.5.0
|
|
25
|
+
Requires-Dist: numpy>=1.24.0
|
|
26
|
+
Requires-Dist: pandas>=2.0.0
|
|
27
|
+
Requires-Dist: pyarrow>=22.0.0
|
|
28
|
+
Requires-Dist: pykalman>=0.11.0
|
|
29
|
+
Requires-Dist: pytorch-lightning>=2.0.0
|
|
30
|
+
Requires-Dist: scikit-learn>=1.7.2
|
|
31
|
+
Requires-Dist: scipy>=1.10.0
|
|
32
|
+
Requires-Dist: sktime>=0.40.1
|
|
33
|
+
Requires-Dist: torch>=2.0.0
|
|
34
|
+
Requires-Dist: twine>=6.2.0
|
|
35
|
+
Provides-Extra: all
|
|
36
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'all'
|
|
37
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'all'
|
|
38
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'all'
|
|
39
|
+
Requires-Dist: pytest>=7.0.0; extra == 'all'
|
|
40
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == 'all'
|
|
41
|
+
Requires-Dist: sktime>=0.27.0; extra == 'all'
|
|
42
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == 'all'
|
|
43
|
+
Provides-Extra: db
|
|
44
|
+
Requires-Dist: sqlalchemy>=2.0.0; extra == 'db'
|
|
45
|
+
Provides-Extra: deep
|
|
46
|
+
Provides-Extra: dev
|
|
47
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
48
|
+
Requires-Dist: pytest>=7.0.0; extra == 'dev'
|
|
49
|
+
Requires-Dist: scikit-learn>=1.0.0; extra == 'dev'
|
|
50
|
+
Provides-Extra: forecasting
|
|
51
|
+
Requires-Dist: sktime[forecasting]>=0.40.1; extra == 'forecasting'
|
|
52
|
+
Provides-Extra: hydra
|
|
53
|
+
Requires-Dist: hydra-core>=1.3.0; extra == 'hydra'
|
|
54
|
+
Requires-Dist: omegaconf>=2.3.0; extra == 'hydra'
|
|
55
|
+
Provides-Extra: transform
|
|
56
|
+
Requires-Dist: sktime>=0.27.0; extra == 'transform'
|
|
@@ -22,7 +22,7 @@ seed: 3 # Random seed (matching original seed=3)
|
|
|
22
22
|
|
|
23
23
|
# Data Handling (used by Dataset, not Model)
|
|
24
24
|
clock: d # Daily clock frequency (all series are daily)
|
|
25
|
-
|
|
25
|
+
scaler: null # No scaler - data should be pre-scaled before passing to Dataset
|
|
26
26
|
|
|
27
27
|
# Frequency mapping (all series are daily)
|
|
28
28
|
# If not specified, all series use clock frequency (d)
|
|
@@ -20,7 +20,7 @@ seed: null # Random seed (None uses default)
|
|
|
20
20
|
|
|
21
21
|
# Data Handling (used by Dataset, not Model)
|
|
22
22
|
clock: m # Monthly clock frequency
|
|
23
|
-
|
|
23
|
+
scaler: standard # Scaler for target series: 'standard', 'robust', 'minmax', 'maxabs', 'quantile', or null
|
|
24
24
|
|
|
25
25
|
# Frequency mapping (optional)
|
|
26
26
|
# If not specified, all series use clock frequency
|
|
@@ -22,7 +22,7 @@ seed: null # Random seed (None uses default)
|
|
|
22
22
|
|
|
23
23
|
# Data Handling (used by Dataset, not Model)
|
|
24
24
|
clock: w # Weekly clock frequency (base frequency for latent factors)
|
|
25
|
-
|
|
25
|
+
scaler: standard # Scaler for target series: 'standard', 'robust', 'minmax', 'maxabs', 'quantile', or null
|
|
26
26
|
|
|
27
27
|
# Frequency mapping for mixed-frequency macro data
|
|
28
28
|
# Clock is weekly (w), so monthly series are slower frequency
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# DFM Configuration for Exchange Rate Datasets
|
|
2
|
+
# Clock: Daily (d) - base frequency for latent factors
|
|
3
|
+
|
|
4
|
+
# EM Algorithm Parameters
|
|
5
|
+
threshold: 1.0e-05
|
|
6
|
+
max_iter: 5000
|
|
7
|
+
|
|
8
|
+
# Numerical Stability Parameters
|
|
9
|
+
clip_ar_coefficients: true
|
|
10
|
+
ar_clip_min: -0.99
|
|
11
|
+
ar_clip_max: 0.99
|
|
12
|
+
use_regularization: true
|
|
13
|
+
regularization_scale: 1.0e-05
|
|
14
|
+
|
|
15
|
+
# Idiosyncratic Component Parameters
|
|
16
|
+
augment_idio: true
|
|
17
|
+
augment_idio_slow: false
|
|
18
|
+
idio_rho0: 0.1
|
|
19
|
+
idio_min_var: 1.0e-08
|
|
20
|
+
|
|
21
|
+
# Data Handling
|
|
22
|
+
clock: d
|
|
23
|
+
scaler: standard
|
|
24
|
+
|
|
25
|
+
# Block Structure
|
|
26
|
+
blocks:
|
|
27
|
+
Block_Global:
|
|
28
|
+
num_factors: 1
|
|
29
|
+
series: [] # Will be populated from data
|
|
30
|
+
|
|
31
|
+
# Frequency mapping
|
|
32
|
+
frequency: {} # Will be populated from data
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
# Reduced series for testing purposes
|
|
7
7
|
|
|
8
8
|
# EM Algorithm Parameters
|
|
9
|
-
ar_lag: 1 # Global AR lag order (applies to all blocks)
|
|
10
9
|
threshold: 1.0e-05 # EM convergence threshold
|
|
11
10
|
max_iter: 5000 # Maximum EM iterations
|
|
12
11
|
|
|
@@ -25,10 +24,8 @@ idio_min_var: 1.0e-08
|
|
|
25
24
|
|
|
26
25
|
# Data Handling
|
|
27
26
|
clock: m # Monthly clock frequency (tutorial uses monthly, adjust to 'd' for daily or 'w' for weekly)
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
# from sklearn.preprocessing import StandardScaler
|
|
31
|
-
# config.target_scaler = StandardScaler()
|
|
27
|
+
scaler: standard # Scaler for all series: 'standard', 'robust', 'minmax', 'maxabs', 'quantile', or null
|
|
28
|
+
# Note: scaler is handled internally by the model, not set on config object
|
|
32
29
|
# Note: nan_method and nan_k are internal constants (not user-configurable)
|
|
33
30
|
|
|
34
31
|
# Block Structure for Financial Data
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
# Target: KOEQUIPTE (Investment, Equipment, Estimation, SA)
|
|
6
6
|
|
|
7
7
|
# EM Algorithm Parameters
|
|
8
|
-
ar_lag: 1 # Global AR lag order (applies to all blocks)
|
|
9
8
|
threshold: 1.0e-05 # EM convergence threshold
|
|
10
9
|
max_iter: 5000 # Maximum EM iterations
|
|
11
10
|
|
|
@@ -24,10 +23,8 @@ idio_min_var: 1.0e-08
|
|
|
24
23
|
|
|
25
24
|
# Data Handling
|
|
26
25
|
clock: w # Weekly clock frequency (base frequency for latent factors)
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
# from sklearn.preprocessing import StandardScaler
|
|
30
|
-
# config.target_scaler = StandardScaler()
|
|
26
|
+
scaler: standard # Scaler for all series: 'standard', 'robust', 'minmax', 'maxabs', 'quantile', or null
|
|
27
|
+
# Note: scaler is handled internally by the model, not set on config object
|
|
31
28
|
# Note: nan_method and nan_k are internal constants (not user-configurable)
|
|
32
29
|
|
|
33
30
|
# Block Structure for Macroeconomic Data
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "dfm-python"
|
|
3
|
-
version = "0.5.
|
|
3
|
+
version = "0.5.60"
|
|
4
4
|
description = "Dynamic Factor Model (DFM) estimation and forecasting in Python"
|
|
5
|
-
readme = "README.md"
|
|
6
5
|
requires-python = ">=3.10"
|
|
7
6
|
license = {text = "MIT"}
|
|
8
7
|
authors = [
|
|
@@ -20,6 +19,7 @@ classifiers = [
|
|
|
20
19
|
"Topic :: Scientific/Engineering",
|
|
21
20
|
]
|
|
22
21
|
dependencies = [
|
|
22
|
+
"build>=1.4.0",
|
|
23
23
|
"einops>=0.8.1",
|
|
24
24
|
"hydra-core>=1.3.2",
|
|
25
25
|
"matplotlib>=3.5.0",
|
|
@@ -32,7 +32,9 @@ Example:
|
|
|
32
32
|
>>> df_processed = df[[col for col in df.columns if col != 'date']]
|
|
33
33
|
>>>
|
|
34
34
|
>>> # Step 2: Create Dataset
|
|
35
|
-
>>>
|
|
35
|
+
>>> from dfm_python.config import DFMConfig
|
|
36
|
+
>>> config = DFMConfig.from_yaml('config/default.yaml')
|
|
37
|
+
>>> dataset = DFMDataset(config=config, data=df_processed)
|
|
36
38
|
>>>
|
|
37
39
|
>>> # Step 3: Create model and load config
|
|
38
40
|
>>> model = DFM()
|
|
@@ -61,7 +63,7 @@ Note: DFMConfig uses frequency dict to specify series (column names -> frequenci
|
|
|
61
63
|
For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
|
|
62
64
|
"""
|
|
63
65
|
|
|
64
|
-
__version__ = "0.5.
|
|
66
|
+
__version__ = "0.5.60"
|
|
65
67
|
|
|
66
68
|
# ============================================================================
|
|
67
69
|
# PUBLIC API DEFINITION
|
|
@@ -102,7 +104,10 @@ from .models.base import BaseFactorModel
|
|
|
102
104
|
from .models.dfm import DFM
|
|
103
105
|
|
|
104
106
|
# DDFM high-level API (PyTorch is mandatory)
|
|
105
|
-
|
|
107
|
+
try:
|
|
108
|
+
from .models.ddfm.ddfm import DDFM
|
|
109
|
+
except ImportError:
|
|
110
|
+
DDFM = None
|
|
106
111
|
|
|
107
112
|
__all__ = [
|
|
108
113
|
# Core classes
|
|
@@ -81,12 +81,7 @@ from .types import (
|
|
|
81
81
|
)
|
|
82
82
|
# Import lazily to avoid circular dependencies
|
|
83
83
|
try:
|
|
84
|
-
from ..
|
|
85
|
-
except ImportError:
|
|
86
|
-
compute_idio_lengths = None
|
|
87
|
-
|
|
88
|
-
try:
|
|
89
|
-
from ..numeric.tent import get_agg_structure, group_by_freq
|
|
84
|
+
from ..models.dfm.tent import get_agg_structure, group_by_freq
|
|
90
85
|
except ImportError:
|
|
91
86
|
get_agg_structure = None
|
|
92
87
|
group_by_freq = None
|
|
@@ -100,7 +95,7 @@ def get_periods_per_year(frequency: str) -> int:
|
|
|
100
95
|
__all__ = [
|
|
101
96
|
# Base classes
|
|
102
97
|
'BaseModelConfig', 'BaseResult',
|
|
103
|
-
# 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import
|
|
98
|
+
# 'DEFAULT_BLOCK_NAME', # Removed to avoid circular import
|
|
104
99
|
# Model-specific configs (from schema.py)
|
|
105
100
|
'DFMConfig', 'DDFMConfig',
|
|
106
101
|
# State-space parameters
|
|
@@ -117,7 +112,6 @@ __all__ = [
|
|
|
117
112
|
'FREQUENCY_HIERARCHY',
|
|
118
113
|
'PERIODS_PER_YEAR',
|
|
119
114
|
'get_periods_per_year',
|
|
120
|
-
'compute_idio_lengths',
|
|
121
115
|
'get_agg_structure',
|
|
122
116
|
'group_by_freq',
|
|
123
117
|
# Type definitions (from types.py)
|
|
@@ -303,7 +303,6 @@ class YamlSource:
|
|
|
303
303
|
_EXCLUDED_KEYS = {
|
|
304
304
|
'defaults', '_target_', '_recursive_', '_convert_',
|
|
305
305
|
'series', 'blocks', 'data', 'output', 'description', 'name', 'target', 'model',
|
|
306
|
-
'nan_method', 'nan_k' # Internal constants, not user-configurable
|
|
307
306
|
}
|
|
308
307
|
main_settings = {k: v for k, v in cfg_dict.items() if k not in _EXCLUDED_KEYS}
|
|
309
308
|
|
|
@@ -65,8 +65,6 @@ from ..constants import (
|
|
|
65
65
|
MIN_EIGENVALUE,
|
|
66
66
|
MAX_EIGENVALUE,
|
|
67
67
|
MIN_DIAGONAL_VARIANCE,
|
|
68
|
-
DEFAULT_NAN_METHOD,
|
|
69
|
-
DEFAULT_NAN_K,
|
|
70
68
|
DEFAULT_CLOCK_FREQUENCY,
|
|
71
69
|
DEFAULT_KDFM_AR_ORDER,
|
|
72
70
|
DEFAULT_KDFM_MA_ORDER,
|
|
@@ -138,7 +136,6 @@ class BaseModelConfig:
|
|
|
138
136
|
# ========================================================================
|
|
139
137
|
clock: str = 'm' # Required: Base frequency for latent factors (global clock): 'd', 'w', 'm', 'q', 'sa', 'a' (defaults to 'm' for monthly)
|
|
140
138
|
target_scaler: Optional[ScalerType] = None # Fitted sklearn scaler instance (StandardScaler, RobustScaler, etc.) for target series only. Must be a fitted scaler object (call .fit() on target data first). Pass scaler object directly, not string. Feature series are assumed to be manually preprocessed. If None, target series are assumed to be already in the desired scale.
|
|
141
|
-
# Note: nan_method and nan_k are internal constants (DEFAULT_NAN_METHOD, DEFAULT_NAN_K) used during initialization only
|
|
142
139
|
|
|
143
140
|
def __post_init__(self):
|
|
144
141
|
"""Validate basic model structure.
|
|
@@ -294,9 +291,6 @@ class DFMConfig(BaseModelConfig):
|
|
|
294
291
|
# - If mixed frequencies detected: augment_idio=True, augment_idio_slow=True (required for tent kernel)
|
|
295
292
|
# These are properties, not config fields - automatically determined from frequency configuration
|
|
296
293
|
|
|
297
|
-
# Kalman Filter Type
|
|
298
|
-
use_cholesky_filter: bool = False # Use CholeskyKalmanFilter for better numerical stability (default: False)
|
|
299
|
-
|
|
300
294
|
# Tent Kernel Weights (for mixed-frequency aggregation)
|
|
301
295
|
tent_weights: Optional[Union[Dict[str, List[float]], Dict[str, np.ndarray]]] = None # Required for mixed-frequency data: tent weights for frequency pairs. Format: {'freq_pair': [weights]} or {'freq': [weights]}. Example: {'m:w': [1, 2, 1]} or {'m': [1, 2, 1]}. Must be specified in config for all slower-frequency pairs.
|
|
302
296
|
|
|
@@ -379,7 +373,11 @@ class DFMConfig(BaseModelConfig):
|
|
|
379
373
|
object.__setattr__(self, '_augment_idio_slow', is_mixed_freq)
|
|
380
374
|
|
|
381
375
|
def to_em_config(self) -> 'EMConfig':
|
|
382
|
-
"""Create EMConfig from DFMConfig consolidated parameters.
|
|
376
|
+
"""Create EMConfig from DFMConfig consolidated parameters.
|
|
377
|
+
|
|
378
|
+
Automatically passes all numerical stability parameters (regularization, ar_clip,
|
|
379
|
+
damping_factor, data_clip) from DFMConfig to EMConfig for use in EM algorithm.
|
|
380
|
+
"""
|
|
383
381
|
from ...functional.em import EMConfig
|
|
384
382
|
from ..constants import DEFAULT_REGULARIZATION, VAR_STABILITY_THRESHOLD
|
|
385
383
|
|
|
@@ -397,6 +395,10 @@ class DFMConfig(BaseModelConfig):
|
|
|
397
395
|
regularization=reg_scale,
|
|
398
396
|
min_norm=min_eigenval,
|
|
399
397
|
max_eigenval=max_eigenval,
|
|
398
|
+
# Pass numerical stability parameters from DFMConfig
|
|
399
|
+
ar_clip=self.ar_clip,
|
|
400
|
+
damping_factor=self.damping_factor,
|
|
401
|
+
data_clip=self.data_clip,
|
|
400
402
|
# Other parameters use defaults from EMConfig
|
|
401
403
|
)
|
|
402
404
|
|
|
@@ -453,7 +455,6 @@ class DFMConfig(BaseModelConfig):
|
|
|
453
455
|
'data_clip': data.get('data_clip', None),
|
|
454
456
|
'regularization': data.get('regularization', None),
|
|
455
457
|
'damping_factor': data.get('damping_factor', None),
|
|
456
|
-
'use_cholesky_filter': data.get('use_cholesky_filter', False),
|
|
457
458
|
'tent_weights': data.get('tent_weights', None),
|
|
458
459
|
}
|
|
459
460
|
|
|
@@ -8,97 +8,12 @@ import numpy as np
|
|
|
8
8
|
from typing import Optional, Any
|
|
9
9
|
|
|
10
10
|
|
|
11
|
-
@dataclass
|
|
12
|
-
class DFMStateSpaceParams:
|
|
13
|
-
"""State-space model parameters for DFM (fitted during model training).
|
|
14
|
-
|
|
15
|
-
These parameters are computed during DFM.fit() and represent the fitted
|
|
16
|
-
state-space model structure. Contains only the state-space parameters,
|
|
17
|
-
not training metadata (loglik, num_iter, converged) which are stored
|
|
18
|
-
separately in checkpoint dicts.
|
|
19
|
-
|
|
20
|
-
Parameters
|
|
21
|
-
----------
|
|
22
|
-
A : np.ndarray
|
|
23
|
-
Transition matrix (m x m) - VAR dynamics for factors
|
|
24
|
-
C : np.ndarray
|
|
25
|
-
Observation matrix (N x m) - factor loadings
|
|
26
|
-
Q : np.ndarray
|
|
27
|
-
Process noise covariance (m x m) - innovation covariance
|
|
28
|
-
R : np.ndarray
|
|
29
|
-
Observation noise covariance (N x N) - typically diagonal
|
|
30
|
-
Z_0 : np.ndarray
|
|
31
|
-
Initial state mean (m,) - initial factor values
|
|
32
|
-
V_0 : np.ndarray
|
|
33
|
-
Initial state covariance (m x m) - initial uncertainty
|
|
34
|
-
"""
|
|
35
|
-
A: np.ndarray # Transition matrix (m x m)
|
|
36
|
-
C: np.ndarray # Observation matrix (N x m)
|
|
37
|
-
Q: np.ndarray # Process noise covariance (m x m)
|
|
38
|
-
R: np.ndarray # Observation noise covariance (N x N)
|
|
39
|
-
Z_0: np.ndarray # Initial state mean (m,)
|
|
40
|
-
V_0: np.ndarray # Initial state covariance (m x m)
|
|
41
|
-
|
|
42
|
-
@classmethod
|
|
43
|
-
def from_model(cls, model: Any) -> 'DFMStateSpaceParams':
|
|
44
|
-
"""Create DFMStateSpaceParams from DFM model instance.
|
|
45
|
-
|
|
46
|
-
Parameters
|
|
47
|
-
----------
|
|
48
|
-
model : DFM
|
|
49
|
-
DFM model instance with fitted parameters
|
|
50
|
-
|
|
51
|
-
Returns
|
|
52
|
-
-------
|
|
53
|
-
DFMStateSpaceParams
|
|
54
|
-
State-space parameters dataclass
|
|
55
|
-
"""
|
|
56
|
-
# Get parameters from model (stored after fit)
|
|
57
|
-
# First check if training_state is already DFMStateSpaceParams (new format)
|
|
58
|
-
if hasattr(model, 'training_state') and model.training_state is not None:
|
|
59
|
-
if isinstance(model.training_state, cls):
|
|
60
|
-
# Already a DFMStateSpaceParams instance
|
|
61
|
-
return model.training_state
|
|
62
|
-
# Backward compatibility: If old format training_state (has A, C, Q, R, Z_0, V_0 attributes)
|
|
63
|
-
if hasattr(model.training_state, 'A'):
|
|
64
|
-
return cls(
|
|
65
|
-
A=model.training_state.A,
|
|
66
|
-
C=model.training_state.C,
|
|
67
|
-
Q=model.training_state.Q,
|
|
68
|
-
R=model.training_state.R,
|
|
69
|
-
Z_0=model.training_state.Z_0,
|
|
70
|
-
V_0=model.training_state.V_0
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
# Get from model attributes (after _update_parameters is called)
|
|
74
|
-
return cls(
|
|
75
|
-
A=getattr(model, 'A', None),
|
|
76
|
-
C=getattr(model, 'C', None),
|
|
77
|
-
Q=getattr(model, 'Q', None),
|
|
78
|
-
R=getattr(model, 'R', None),
|
|
79
|
-
Z_0=getattr(model, 'Z_0', None),
|
|
80
|
-
V_0=getattr(model, 'V_0', None)
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
def apply_to_model(self, model: Any) -> None:
|
|
84
|
-
"""Apply state-space parameters to DFM model instance.
|
|
85
|
-
|
|
86
|
-
Parameters
|
|
87
|
-
----------
|
|
88
|
-
model : DFM
|
|
89
|
-
DFM model instance to update
|
|
90
|
-
"""
|
|
91
|
-
model._update_parameters(
|
|
92
|
-
self.A, self.C, self.Q, self.R, self.Z_0, self.V_0
|
|
93
|
-
)
|
|
94
|
-
|
|
95
|
-
|
|
96
11
|
@dataclass
|
|
97
12
|
class DFMModelState:
|
|
98
|
-
"""DFM model structure
|
|
13
|
+
"""DFM model state including structure, mixed-frequency parameters, and state-space parameters.
|
|
99
14
|
|
|
100
|
-
Consolidates
|
|
101
|
-
|
|
15
|
+
Consolidates all DFM model state for checkpointing: model structure, mixed-frequency
|
|
16
|
+
configuration, and fitted state-space parameters.
|
|
102
17
|
|
|
103
18
|
Attributes
|
|
104
19
|
----------
|
|
@@ -128,6 +43,18 @@ class DFMModelState:
|
|
|
128
43
|
Indicator for idiosyncratic components
|
|
129
44
|
max_lag_size : int, optional
|
|
130
45
|
Maximum lag size for state dimension
|
|
46
|
+
A : np.ndarray, optional
|
|
47
|
+
Transition matrix (m x m) - VAR dynamics for factors
|
|
48
|
+
C : np.ndarray, optional
|
|
49
|
+
Observation matrix (N x m) - factor loadings
|
|
50
|
+
Q : np.ndarray, optional
|
|
51
|
+
Process noise covariance (m x m) - innovation covariance
|
|
52
|
+
R : np.ndarray, optional
|
|
53
|
+
Observation noise covariance (N x N) - typically diagonal
|
|
54
|
+
Z_0 : np.ndarray, optional
|
|
55
|
+
Initial state mean (m,) - initial factor values
|
|
56
|
+
V_0 : np.ndarray, optional
|
|
57
|
+
Initial state covariance (m x m) - initial uncertainty
|
|
131
58
|
"""
|
|
132
59
|
num_factors: int
|
|
133
60
|
r: np.ndarray
|
|
@@ -142,6 +69,13 @@ class DFMModelState:
|
|
|
142
69
|
frequencies: Optional[np.ndarray] = None
|
|
143
70
|
idio_indicator: Optional[np.ndarray] = None
|
|
144
71
|
max_lag_size: Optional[int] = None
|
|
72
|
+
# State-space parameters (fitted during training)
|
|
73
|
+
A: Optional[np.ndarray] = None
|
|
74
|
+
C: Optional[np.ndarray] = None
|
|
75
|
+
Q: Optional[np.ndarray] = None
|
|
76
|
+
R: Optional[np.ndarray] = None
|
|
77
|
+
Z_0: Optional[np.ndarray] = None
|
|
78
|
+
V_0: Optional[np.ndarray] = None
|
|
145
79
|
|
|
146
80
|
@classmethod
|
|
147
81
|
def from_model(cls, model: Any) -> 'DFMModelState':
|
|
@@ -157,6 +91,27 @@ class DFMModelState:
|
|
|
157
91
|
DFMModelState
|
|
158
92
|
Model state dataclass
|
|
159
93
|
"""
|
|
94
|
+
# Get state-space parameters from training_state if available
|
|
95
|
+
A = C = Q = R = Z_0 = V_0 = None
|
|
96
|
+
if hasattr(model, 'training_state') and model.training_state is not None:
|
|
97
|
+
# Handle both old DFMStateSpaceParams format and new DFMModelState format
|
|
98
|
+
ts = model.training_state
|
|
99
|
+
if hasattr(ts, 'A'):
|
|
100
|
+
A = ts.A
|
|
101
|
+
C = ts.C
|
|
102
|
+
Q = ts.Q
|
|
103
|
+
R = ts.R
|
|
104
|
+
Z_0 = ts.Z_0
|
|
105
|
+
V_0 = ts.V_0
|
|
106
|
+
else:
|
|
107
|
+
# Fallback: get from model attributes directly
|
|
108
|
+
A = getattr(model, 'A', None)
|
|
109
|
+
C = getattr(model, 'C', None)
|
|
110
|
+
Q = getattr(model, 'Q', None)
|
|
111
|
+
R = getattr(model, 'R', None)
|
|
112
|
+
Z_0 = getattr(model, 'Z_0', None)
|
|
113
|
+
V_0 = getattr(model, 'V_0', None)
|
|
114
|
+
|
|
160
115
|
return cls(
|
|
161
116
|
num_factors=model.num_factors,
|
|
162
117
|
r=model.r,
|
|
@@ -170,7 +125,13 @@ class DFMModelState:
|
|
|
170
125
|
tent_weights_dict=getattr(model, '_tent_weights_dict', None),
|
|
171
126
|
frequencies=getattr(model, '_frequencies', None),
|
|
172
127
|
idio_indicator=getattr(model, '_idio_indicator', None),
|
|
173
|
-
max_lag_size=getattr(model, '_max_lag_size', None)
|
|
128
|
+
max_lag_size=getattr(model, '_max_lag_size', None),
|
|
129
|
+
A=A,
|
|
130
|
+
C=C,
|
|
131
|
+
Q=Q,
|
|
132
|
+
R=R,
|
|
133
|
+
Z_0=Z_0,
|
|
134
|
+
V_0=V_0
|
|
174
135
|
)
|
|
175
136
|
|
|
176
137
|
def apply_to_model(self, model: Any) -> None:
|
|
@@ -194,6 +155,12 @@ class DFMModelState:
|
|
|
194
155
|
model._frequencies = self.frequencies
|
|
195
156
|
model._idio_indicator = self.idio_indicator
|
|
196
157
|
model._max_lag_size = self.max_lag_size
|
|
158
|
+
|
|
159
|
+
# Apply state-space parameters if available
|
|
160
|
+
if self.A is not None and self.C is not None and self.Q is not None:
|
|
161
|
+
model._update_parameters(
|
|
162
|
+
self.A, self.C, self.Q, self.R, self.Z_0, self.V_0
|
|
163
|
+
)
|
|
197
164
|
|
|
198
165
|
@dataclass
|
|
199
166
|
class DDFMTrainingState:
|
|
@@ -277,3 +244,6 @@ class DDFMStateSpaceParams:
|
|
|
277
244
|
H: np.ndarray # Observation matrix (N x m) - theta in paper
|
|
278
245
|
R: np.ndarray # Observation noise covariance (N x N)
|
|
279
246
|
|
|
247
|
+
# Backward compatibility alias
|
|
248
|
+
DFMStateSpaceParams = DFMModelState
|
|
249
|
+
|