dfm-python 0.1.6__py3-none-any.whl → 0.2.0__py3-none-any.whl
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/__init__.py +152 -28
- dfm_python/config.py +1026 -287
- dfm_python/data_loader.py +475 -217
- dfm_python/dfm.py +1584 -1030
- dfm_python/dfm_api.py +630 -0
- dfm_python/kalman.py +4 -12
- dfm_python/news.py +81 -41
- dfm_python/utils/__init__.py +0 -2
- dfm_python/utils/aggregation.py +10 -11
- dfm_python/utils/data_utils.py +43 -8
- dfm_python-0.2.0.dist-info/METADATA +647 -0
- dfm_python-0.2.0.dist-info/RECORD +14 -0
- dfm_python-0.1.6.dist-info/METADATA +0 -572
- dfm_python-0.1.6.dist-info/RECORD +0 -13
- {dfm_python-0.1.6.dist-info → dfm_python-0.2.0.dist-info}/WHEEL +0 -0
- {dfm_python-0.1.6.dist-info → dfm_python-0.2.0.dist-info}/licenses/LICENSE +0 -0
dfm_python/__init__.py
CHANGED
|
@@ -1,60 +1,184 @@
|
|
|
1
1
|
"""Dynamic Factor Model (DFM) package for Python.
|
|
2
2
|
|
|
3
3
|
This package implements a comprehensive Dynamic Factor Model framework with support for:
|
|
4
|
-
- Mixed-frequency time series data (
|
|
4
|
+
- Mixed-frequency time series data (monthly, quarterly, semi-annual, annual)
|
|
5
5
|
- Clock-based synchronization of latent factors
|
|
6
6
|
- Tent kernel aggregation for low-to-high frequency mapping
|
|
7
7
|
- Expectation-Maximization (EM) algorithm for parameter estimation
|
|
8
8
|
- Kalman filtering and smoothing for factor extraction
|
|
9
9
|
- News decomposition for nowcasting
|
|
10
10
|
|
|
11
|
-
The package
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
The package implements a clock-based approach to mixed-frequency DFMs, where all latent
|
|
12
|
+
factors (global and block-level) are synchronized to a common "clock" frequency, typically
|
|
13
|
+
monthly. Lower-frequency observed variables are mapped to higher-frequency latent states
|
|
14
|
+
using deterministic tent kernels in the observation equation.
|
|
15
|
+
|
|
16
|
+
Note: Higher frequencies (daily, weekly) than the clock are not supported. If any series
|
|
17
|
+
has a frequency faster than the clock, a ValueError will be raised.
|
|
15
18
|
|
|
16
19
|
Key Features:
|
|
17
|
-
- Unified configuration system (YAML/
|
|
20
|
+
- Unified configuration system (YAML with Hydra/OmegaConf, or direct DFMConfig objects)
|
|
18
21
|
- Flexible block structure for factor modeling
|
|
19
22
|
- Robust handling of missing data
|
|
20
23
|
- Comprehensive transformation support
|
|
21
24
|
- News decomposition for forecast updates
|
|
22
25
|
|
|
23
|
-
Example:
|
|
24
|
-
>>>
|
|
26
|
+
Example (High-level API - Recommended):
|
|
27
|
+
>>> import dfm_python as dfm
|
|
28
|
+
>>> dfm.load_config('config/default.yaml')
|
|
29
|
+
>>> dfm.load_data('data/sample_data.csv')
|
|
30
|
+
>>> dfm.train(max_iter=1)
|
|
31
|
+
>>> Xf, Zf = dfm.predict(horizon=6)
|
|
32
|
+
>>> dfm.plot(kind='factor', factor_index=0, forecast_horizon=6, save_path='outputs/factor_forecast.png')
|
|
33
|
+
>>> factors = dfm.get_result().Z # Access factors via result
|
|
34
|
+
|
|
35
|
+
Example (Low-level API - For advanced usage):
|
|
36
|
+
>>> from dfm_python import DFM, DFMConfig, SeriesConfig
|
|
37
|
+
>>> from dfm_python.data_loader import load_data
|
|
38
|
+
>>> # Option 1: Load from YAML
|
|
25
39
|
>>> config = load_config('config.yaml')
|
|
26
|
-
>>>
|
|
27
|
-
>>>
|
|
40
|
+
>>> # Option 2: Create directly
|
|
41
|
+
>>> config = DFMConfig(
|
|
42
|
+
... series=[SeriesConfig(frequency='m', transformation='lin', blocks=[1], series_id='series1')],
|
|
43
|
+
... block_names=['Global']
|
|
44
|
+
... )
|
|
45
|
+
>>> X, Time, _ = load_data('data.csv', config) # or use database adapter
|
|
46
|
+
>>> model = DFM()
|
|
47
|
+
>>> result = model.fit(X, config)
|
|
28
48
|
>>> factors = result.Z # Extract estimated factors
|
|
29
49
|
|
|
30
|
-
For detailed documentation, see the README.md file.
|
|
50
|
+
For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
|
|
31
51
|
"""
|
|
32
52
|
|
|
33
|
-
__version__ = "0.
|
|
53
|
+
__version__ = "0.2.0"
|
|
34
54
|
|
|
35
|
-
from .config import DFMConfig
|
|
36
|
-
from .
|
|
37
|
-
|
|
55
|
+
from .config import DFMConfig, SeriesConfig, BlockConfig, Params, DEFAULT_GLOBAL_BLOCK_NAME
|
|
56
|
+
from .config import (
|
|
57
|
+
ConfigSource,
|
|
58
|
+
YamlSource,
|
|
59
|
+
DictSource,
|
|
60
|
+
SpecCSVSource,
|
|
61
|
+
HydraSource,
|
|
62
|
+
MergedConfigSource,
|
|
63
|
+
make_config_source,
|
|
38
64
|
)
|
|
39
|
-
from .
|
|
65
|
+
from .data_loader import transform_data
|
|
66
|
+
from .dfm import DFMResult, calculate_rmse, diagnose_series, print_series_diagnosis
|
|
67
|
+
from .dfm import DFM as _DFMCore # Core DFM class from dfm.py
|
|
40
68
|
from .kalman import run_kf, skf, fis, miss_data
|
|
41
69
|
from .news import update_nowcast, news_dfm, para_const
|
|
42
70
|
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
71
|
+
# Import high-level API (extends core DFM with convenience methods)
|
|
72
|
+
from .dfm_api import DFM, _dfm_instance, from_yaml, from_spec, from_spec_df, from_dict
|
|
73
|
+
|
|
74
|
+
# Module-level API: expose singleton instance methods and properties
|
|
75
|
+
# This allows: import dfm_python as dfm; dfm.load_config(...); dfm.result
|
|
76
|
+
def load_config(
|
|
77
|
+
source=None,
|
|
78
|
+
*,
|
|
79
|
+
yaml=None,
|
|
80
|
+
mapping=None,
|
|
81
|
+
spec=None,
|
|
82
|
+
hydra=None,
|
|
83
|
+
base=None,
|
|
84
|
+
override=None,
|
|
85
|
+
config=None,
|
|
86
|
+
):
|
|
87
|
+
"""Load configuration (module-level convenience function).
|
|
88
|
+
|
|
89
|
+
See DFM.load_config() for parameter documentation.
|
|
90
|
+
"""
|
|
91
|
+
return _dfm_instance.load_config(
|
|
92
|
+
source=source,
|
|
93
|
+
yaml=yaml,
|
|
94
|
+
mapping=mapping,
|
|
95
|
+
spec=spec,
|
|
96
|
+
hydra=hydra,
|
|
97
|
+
base=base,
|
|
98
|
+
override=override,
|
|
99
|
+
config=config,
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
def load_data(data_path=None, data=None, **kwargs):
|
|
103
|
+
"""Load data (module-level convenience function)."""
|
|
104
|
+
return _dfm_instance.load_data(data_path=data_path, data=data, **kwargs)
|
|
105
|
+
|
|
106
|
+
def train(threshold=None, max_iter=None, **kwargs):
|
|
107
|
+
"""Train the model (module-level convenience function)."""
|
|
108
|
+
return _dfm_instance.train(threshold=threshold, max_iter=max_iter, **kwargs)
|
|
109
|
+
|
|
110
|
+
def predict(horizon=12, **kwargs):
|
|
111
|
+
"""Forecast using the trained model (module-level convenience function)."""
|
|
112
|
+
return _dfm_instance.predict(horizon=horizon, **kwargs)
|
|
113
|
+
|
|
114
|
+
def plot(**kwargs):
|
|
115
|
+
"""Plot common visualizations (module-level convenience function)."""
|
|
116
|
+
return _dfm_instance.plot(**kwargs)
|
|
117
|
+
|
|
118
|
+
def reset():
|
|
119
|
+
"""Reset state (module-level convenience function)."""
|
|
120
|
+
return _dfm_instance.reset()
|
|
121
|
+
|
|
122
|
+
# Expose properties as module-level attributes
|
|
123
|
+
# Use property-like access via functions or direct attribute access
|
|
124
|
+
# Since 'config' conflicts with the config module, we'll use a different approach
|
|
125
|
+
# Users can access: dfm.get_config(), dfm.get_data(), dfm.get_result()
|
|
126
|
+
def get_config():
|
|
127
|
+
"""Get current configuration."""
|
|
128
|
+
return _dfm_instance.config
|
|
129
|
+
|
|
130
|
+
def get_data():
|
|
131
|
+
"""Get current data matrix."""
|
|
132
|
+
return _dfm_instance.data
|
|
133
|
+
|
|
134
|
+
def get_time():
|
|
135
|
+
"""Get current time index."""
|
|
136
|
+
return _dfm_instance.time
|
|
137
|
+
|
|
138
|
+
def get_result():
|
|
139
|
+
"""Get training result."""
|
|
140
|
+
return _dfm_instance.result
|
|
141
|
+
|
|
142
|
+
def get_original_data():
|
|
143
|
+
"""Get original (untransformed) data matrix."""
|
|
144
|
+
return _dfm_instance.original_data
|
|
145
|
+
|
|
146
|
+
# For direct attribute access, we'll use __getattr__ but handle config module conflict
|
|
147
|
+
|
|
148
|
+
def __getattr__(name):
|
|
149
|
+
"""Allow access to DFM instance properties at module level."""
|
|
150
|
+
# Handle special cases that conflict with submodules
|
|
151
|
+
if name == 'config' and _dfm_instance.config is not None:
|
|
152
|
+
return _dfm_instance.config
|
|
153
|
+
elif name == 'data':
|
|
154
|
+
return _dfm_instance.data
|
|
155
|
+
elif name == 'time':
|
|
156
|
+
return _dfm_instance.time
|
|
157
|
+
elif name == 'result':
|
|
158
|
+
return _dfm_instance.result
|
|
159
|
+
elif name == 'original_data':
|
|
160
|
+
return _dfm_instance.original_data
|
|
161
|
+
# For other attributes, try normal import
|
|
162
|
+
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
47
163
|
|
|
48
164
|
__all__ = [
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
'
|
|
53
|
-
|
|
54
|
-
'
|
|
165
|
+
# Core classes
|
|
166
|
+
'DFMConfig', 'SeriesConfig', 'BlockConfig', 'Params', 'DFM',
|
|
167
|
+
# Constants
|
|
168
|
+
'DEFAULT_GLOBAL_BLOCK_NAME',
|
|
169
|
+
# Config sources
|
|
170
|
+
'ConfigSource', 'YamlSource', 'DictSource', 'SpecCSVSource', 'HydraSource',
|
|
171
|
+
'MergedConfigSource', 'make_config_source',
|
|
172
|
+
# High-level API (module-level - recommended)
|
|
173
|
+
'load_config',
|
|
174
|
+
'load_data', 'train', 'predict', 'plot', 'reset',
|
|
175
|
+
'get_config', 'get_data', 'get_time', 'get_result', 'get_original_data',
|
|
176
|
+
# Convenience constructors (cleaner API)
|
|
177
|
+
'from_yaml', 'from_spec', 'from_spec_df', 'from_dict',
|
|
178
|
+
# Low-level API (functional interface - advanced usage)
|
|
179
|
+
'transform_data',
|
|
180
|
+
'DFMResult', 'calculate_rmse', 'diagnose_series', 'print_series_diagnosis',
|
|
55
181
|
'run_kf', 'skf', 'fis', 'miss_data',
|
|
56
182
|
'update_nowcast', 'news_dfm', 'para_const',
|
|
57
|
-
# Deprecated aliases
|
|
58
|
-
'ModelSpec', 'load_spec',
|
|
59
183
|
]
|
|
60
184
|
|