dfm-python 0.2.7__py3-none-any.whl → 0.2.9__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 +6 -29
- dfm_python/api.py +38 -19
- dfm_python/config.py +13 -14
- dfm_python/config_sources.py +354 -59
- dfm_python/core/diagnostics.py +215 -6
- dfm_python/core/em.py +49 -49
- dfm_python/core/helpers.py +76 -0
- dfm_python/core/numeric.py +7 -7
- dfm_python/data.py +1 -51
- dfm_python/dfm.py +4 -1
- dfm_python/news.py +14 -22
- dfm_python/utils.py +4 -7
- {dfm_python-0.2.7.dist-info → dfm_python-0.2.9.dist-info}/METADATA +4 -10
- dfm_python-0.2.9.dist-info/RECORD +18 -0
- dfm_python-0.2.7.dist-info/RECORD +0 -18
- {dfm_python-0.2.7.dist-info → dfm_python-0.2.9.dist-info}/WHEEL +0 -0
- {dfm_python-0.2.7.dist-info → dfm_python-0.2.9.dist-info}/licenses/LICENSE +0 -0
dfm_python/__init__.py
CHANGED
|
@@ -50,22 +50,17 @@ Example (Low-level API - For advanced usage):
|
|
|
50
50
|
For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
|
|
51
51
|
"""
|
|
52
52
|
|
|
53
|
-
__version__ = "0.2.
|
|
53
|
+
__version__ = "0.2.9"
|
|
54
54
|
|
|
55
|
-
from .config import DFMConfig, SeriesConfig, BlockConfig, Params, DEFAULT_GLOBAL_BLOCK_NAME
|
|
56
55
|
from .config import (
|
|
57
|
-
|
|
58
|
-
YamlSource,
|
|
59
|
-
|
|
60
|
-
SpecCSVSource,
|
|
61
|
-
HydraSource,
|
|
62
|
-
MergedConfigSource,
|
|
63
|
-
make_config_source,
|
|
56
|
+
DFMConfig, SeriesConfig, BlockConfig, Params, DEFAULT_GLOBAL_BLOCK_NAME,
|
|
57
|
+
ConfigSource, YamlSource, DictSource, SpecCSVSource, HydraSource,
|
|
58
|
+
MergedConfigSource, make_config_source,
|
|
64
59
|
)
|
|
65
60
|
from .data import transform_data
|
|
66
61
|
from .dfm import DFMResult
|
|
67
62
|
from .core import calculate_rmse, diagnose_series, print_series_diagnosis
|
|
68
|
-
from .dfm import
|
|
63
|
+
from .dfm import DFMCore # Core DFM class from dfm.py
|
|
69
64
|
from .kalman import run_kf, skf, fis, miss_data
|
|
70
65
|
from .news import update_nowcast, news_dfm, para_const
|
|
71
66
|
|
|
@@ -100,27 +95,9 @@ def get_original_data():
|
|
|
100
95
|
"""Get original (untransformed) data matrix."""
|
|
101
96
|
return _dfm_instance.original_data
|
|
102
97
|
|
|
103
|
-
# For direct attribute access, we'll use __getattr__ but handle config module conflict
|
|
104
|
-
|
|
105
|
-
def __getattr__(name):
|
|
106
|
-
"""Allow access to DFM instance properties at module level."""
|
|
107
|
-
# Handle special cases that conflict with submodules
|
|
108
|
-
if name == 'config' and _dfm_instance.config is not None:
|
|
109
|
-
return _dfm_instance.config
|
|
110
|
-
elif name == 'data':
|
|
111
|
-
return _dfm_instance.data
|
|
112
|
-
elif name == 'time':
|
|
113
|
-
return _dfm_instance.time
|
|
114
|
-
elif name == 'result':
|
|
115
|
-
return _dfm_instance.result
|
|
116
|
-
elif name == 'original_data':
|
|
117
|
-
return _dfm_instance.original_data
|
|
118
|
-
# For other attributes, try normal import
|
|
119
|
-
raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
|
|
120
|
-
|
|
121
98
|
__all__ = [
|
|
122
99
|
# Core classes
|
|
123
|
-
'DFMConfig', 'SeriesConfig', 'BlockConfig', 'Params', 'DFM',
|
|
100
|
+
'DFMConfig', 'SeriesConfig', 'BlockConfig', 'Params', 'DFM', 'DFMCore',
|
|
124
101
|
# Constants
|
|
125
102
|
'DEFAULT_GLOBAL_BLOCK_NAME',
|
|
126
103
|
# Config sources
|
dfm_python/api.py
CHANGED
|
@@ -29,11 +29,11 @@ from .config import (
|
|
|
29
29
|
ConfigSource,
|
|
30
30
|
MergedConfigSource,
|
|
31
31
|
)
|
|
32
|
-
from .dfm import
|
|
32
|
+
from .dfm import DFMCore, DFMResult
|
|
33
33
|
from .core.helpers import safe_get_method, safe_get_attr
|
|
34
34
|
|
|
35
35
|
|
|
36
|
-
class DFM(
|
|
36
|
+
class DFM(DFMCore):
|
|
37
37
|
"""High-level API for Dynamic Factor Model estimation.
|
|
38
38
|
|
|
39
39
|
This class provides a simple, object-oriented interface for DFM operations.
|
|
@@ -368,29 +368,48 @@ def from_yaml(yaml_path: Union[str, Path]) -> DFM:
|
|
|
368
368
|
return _dfm_instance.load_config(yaml=yaml_path)
|
|
369
369
|
|
|
370
370
|
|
|
371
|
-
def from_spec(
|
|
372
|
-
|
|
373
|
-
|
|
371
|
+
def from_spec(
|
|
372
|
+
csv_path: Union[str, Path],
|
|
373
|
+
output_dir: Optional[Union[str, Path]] = None,
|
|
374
|
+
series_filename: Optional[str] = None,
|
|
375
|
+
blocks_filename: Optional[str] = None
|
|
376
|
+
) -> Tuple[Path, Path]:
|
|
377
|
+
"""Convert spec CSV file to YAML configuration files.
|
|
374
378
|
|
|
375
|
-
|
|
376
|
-
|
|
379
|
+
This function reads a spec CSV file and generates two YAML files:
|
|
380
|
+
- config/series/{basename}.yaml - series definitions
|
|
381
|
+
- config/blocks/{basename}.yaml - block definitions
|
|
377
382
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
383
|
+
Parameters
|
|
384
|
+
----------
|
|
385
|
+
csv_path : str or Path
|
|
386
|
+
Path to the spec CSV file
|
|
387
|
+
output_dir : str or Path, optional
|
|
388
|
+
Output directory for YAML files. Defaults to config/ directory relative to CSV.
|
|
389
|
+
series_filename : str, optional
|
|
390
|
+
Custom filename for series YAML (without .yaml extension).
|
|
391
|
+
Defaults to CSV basename.
|
|
392
|
+
blocks_filename : str, optional
|
|
393
|
+
Custom filename for blocks YAML (without .yaml extension).
|
|
394
|
+
Defaults to CSV basename.
|
|
395
|
+
|
|
396
|
+
Returns
|
|
397
|
+
-------
|
|
398
|
+
Tuple[Path, Path]
|
|
399
|
+
Paths to generated series YAML and blocks YAML files
|
|
400
|
+
|
|
401
|
+
Examples
|
|
402
|
+
--------
|
|
403
|
+
>>> series_path, blocks_path = from_spec('data/sample_spec.csv')
|
|
404
|
+
>>> # Creates config/series/sample_spec.yaml and config/blocks/sample_spec.yaml
|
|
405
|
+
"""
|
|
406
|
+
from .config_sources import from_spec as _from_spec
|
|
407
|
+
return _from_spec(csv_path, output_dir, series_filename, blocks_filename)
|
|
389
408
|
|
|
390
409
|
|
|
391
410
|
def from_spec_df(spec_df: pd.DataFrame, params: Optional[Params] = None) -> DFM:
|
|
392
411
|
"""Load configuration from spec DataFrame (convenience constructor)."""
|
|
393
|
-
from .
|
|
412
|
+
from .config_sources import _load_config_from_dataframe
|
|
394
413
|
|
|
395
414
|
if params is None:
|
|
396
415
|
params = Params()
|
dfm_python/config.py
CHANGED
|
@@ -21,6 +21,7 @@ from config_sources for backward compatibility.
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
import numpy as np
|
|
24
|
+
import warnings
|
|
24
25
|
from typing import List, Optional, Dict, Any, Union
|
|
25
26
|
from dataclasses import dataclass, field
|
|
26
27
|
|
|
@@ -102,10 +103,14 @@ class SeriesConfig:
|
|
|
102
103
|
Unique identifier (auto-generated if None)
|
|
103
104
|
series_name : str, optional
|
|
104
105
|
Human-readable name (defaults to series_id if None)
|
|
105
|
-
units : str
|
|
106
|
-
Units of measurement
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
units : str, optional
|
|
107
|
+
Units of measurement (optional metadata for display purposes only).
|
|
108
|
+
Used in news decomposition output for readability. Not used in model estimation.
|
|
109
|
+
release_date : int, optional
|
|
110
|
+
Release date information for pseudo real-time nowcasting.
|
|
111
|
+
- Positive value (1-31): Day of month when data is released
|
|
112
|
+
- Negative value: Days before end of previous month when data is released
|
|
113
|
+
Example: 25 = released on 25th of each month, -5 = released 5 days before end of previous month
|
|
109
114
|
"""
|
|
110
115
|
# Required fields (no defaults)
|
|
111
116
|
frequency: str
|
|
@@ -114,9 +119,8 @@ class SeriesConfig:
|
|
|
114
119
|
# Optional fields (with defaults - must come after required fields)
|
|
115
120
|
series_id: Optional[str] = None # Auto-generated if None: "series_0", "series_1", etc.
|
|
116
121
|
series_name: Optional[str] = None # Optional metadata for display
|
|
117
|
-
units: str =
|
|
118
|
-
|
|
119
|
-
aggregate: Optional[str] = None # Aggregation method (deprecated: higher frequencies than clock are not supported)
|
|
122
|
+
units: Optional[str] = None # Optional metadata for display only (used in news.py output)
|
|
123
|
+
release_date: Optional[int] = None # Release date for pseudo real-time nowcasting
|
|
120
124
|
|
|
121
125
|
def __post_init__(self):
|
|
122
126
|
"""Validate fields after initialization."""
|
|
@@ -716,9 +720,7 @@ class DFMConfig:
|
|
|
716
720
|
blocks=series_blocks,
|
|
717
721
|
series_id=get_list_value('SeriesID', i, None),
|
|
718
722
|
series_name=get_list_value('SeriesName', i, None),
|
|
719
|
-
units=
|
|
720
|
-
category=str(get_list_value('Category', i, '')),
|
|
721
|
-
aggregate=get_list_value('Aggregate', i, None)
|
|
723
|
+
units=get_list_value('Units', i, None) # Optional, for display only
|
|
722
724
|
))
|
|
723
725
|
|
|
724
726
|
# Convert block_names to blocks dict
|
|
@@ -805,9 +807,7 @@ class DFMConfig:
|
|
|
805
807
|
frequency=series_cfg.get('frequency', 'm'),
|
|
806
808
|
transformation=series_cfg.get('transformation', 'lin'),
|
|
807
809
|
blocks=series_blocks,
|
|
808
|
-
units=series_cfg.get('units',
|
|
809
|
-
category=series_cfg.get('category', ''),
|
|
810
|
-
aggregate=series_cfg.get('aggregate', None) # Deprecated
|
|
810
|
+
units=series_cfg.get('units', None) # Optional, for display only
|
|
811
811
|
))
|
|
812
812
|
|
|
813
813
|
# Convert blocks_dict to BlockConfig dict
|
|
@@ -1031,7 +1031,6 @@ def validate_transformation(transformation: str) -> str:
|
|
|
1031
1031
|
>>> validate_transformation('unknown') # Issues warning but returns value
|
|
1032
1032
|
'unknown'
|
|
1033
1033
|
"""
|
|
1034
|
-
import warnings
|
|
1035
1034
|
if transformation not in _VALID_TRANSFORMATIONS:
|
|
1036
1035
|
warnings.warn(f"Unknown transformation code: {transformation}. Will use untransformed data.")
|
|
1037
1036
|
return transformation
|