dfm-python 0.4.0__py3-none-any.whl → 0.4.2__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.
Files changed (49) hide show
  1. dfm_python/__init__.py +77 -141
  2. dfm_python/config/__init__.py +18 -18
  3. dfm_python/config/{io.py → adapter.py} +188 -198
  4. dfm_python/config/results.py +36 -11
  5. dfm_python/config/schema.py +375 -149
  6. dfm_python/config/utils.py +479 -25
  7. dfm_python/data/__init__.py +52 -0
  8. dfm_python/data/dataloader.py +97 -0
  9. dfm_python/data/dataset.py +154 -0
  10. dfm_python/{transformations/transformers.py → data/transformation.py} +40 -47
  11. dfm_python/{transformations → data}/utils.py +2 -2
  12. dfm_python/encoder/__init__.py +8 -2
  13. dfm_python/encoder/base.py +111 -0
  14. dfm_python/encoder/pca.py +142 -3
  15. dfm_python/encoder/vae.py +262 -3
  16. dfm_python/lightning/__init__.py +9 -7
  17. dfm_python/lightning/data_module.py +364 -170
  18. dfm_python/lightning/ddfm_module.py +33 -6
  19. dfm_python/logger/__init__.py +2 -0
  20. dfm_python/logger/inference_logger.py +60 -17
  21. dfm_python/logger/logger.py +13 -3
  22. dfm_python/logger/train_logger.py +269 -45
  23. dfm_python/models/__init__.py +8 -20
  24. dfm_python/models/base.py +168 -27
  25. dfm_python/models/ddfm.py +1046 -572
  26. dfm_python/models/dfm.py +676 -314
  27. dfm_python/models/estimation.py +42 -22
  28. dfm_python/nowcast/helpers.py +30 -226
  29. dfm_python/nowcast/nowcast.py +0 -3
  30. dfm_python/nowcast/utils.py +9 -10
  31. dfm_python/ssm/em.py +395 -108
  32. dfm_python/ssm/kalman.py +1 -1
  33. dfm_python/ssm/utils.py +2 -1
  34. dfm_python/trainer/__init__.py +727 -8
  35. dfm_python/trainer/ddfm.py +149 -168
  36. dfm_python/trainer/dfm.py +130 -128
  37. dfm_python/utils/__init__.py +19 -49
  38. dfm_python/utils/data.py +28 -192
  39. dfm_python/utils/helpers.py +19 -98
  40. dfm_python/utils/statespace.py +43 -72
  41. {dfm_python-0.4.0.dist-info → dfm_python-0.4.2.dist-info}/METADATA +7 -1
  42. dfm_python-0.4.2.dist-info/RECORD +52 -0
  43. dfm_python/config/params.py +0 -202
  44. dfm_python/config/structure.py +0 -457
  45. dfm_python/transformations/__init__.py +0 -35
  46. dfm_python/transformations/sktime.py +0 -40
  47. dfm_python-0.4.0.dist-info/RECORD +0 -53
  48. {dfm_python-0.4.0.dist-info → dfm_python-0.4.2.dist-info}/WHEEL +0 -0
  49. {dfm_python-0.4.0.dist-info → dfm_python-0.4.2.dist-info}/licenses/LICENSE +0 -0
dfm_python/__init__.py CHANGED
@@ -7,7 +7,7 @@ This package implements a comprehensive Dynamic Factor Model framework with supp
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
- - Deep Dynamic Factor Models (DDFM) with nonlinear encoders (optional, requires PyTorch)
10
+ - Deep Dynamic Factor Models (DDFM) with nonlinear encoders (requires PyTorch)
11
11
 
12
12
  The package implements a clock-based approach to mixed-frequency DFMs, where all latent
13
13
  factors (global and block-level) are synchronized to a common "clock" frequency, typically
@@ -18,73 +18,56 @@ Note: Higher frequencies (daily, weekly) than the clock are not supported. If an
18
18
  has a frequency faster than the clock, a ValueError will be raised.
19
19
 
20
20
  Key Features:
21
- - Unified configuration system (YAML with Hydra/OmegaConf, or direct DFMConfig objects)
21
+ - Hydra-based configuration (YAML files) - primary configuration method
22
+ - Expects preprocessed data from users - package applies internal transformations automatically
22
23
  - Flexible block structure for factor modeling
23
- - Robust handling of missing data
24
- - Comprehensive transformation support
24
+ - Robust handling of missing data (internal spline interpolation)
25
+ - Automatic standardization and data clipping
25
26
  - News decomposition for forecast updates
26
27
 
27
- Example (High-level API - Recommended):
28
- >>> import dfm_python as dfm
29
- >>> from dfm_python.lightning import DFMDataModule
30
- >>> from sktime.transformations.compose import ColumnTransformer
28
+ Example (Standard Lightning Pattern):
29
+ >>> from dfm_python import DFM, DFMDataModule, DFMTrainer
30
+ >>> import polars as pl
31
31
  >>>
32
- >>> # Linear DFM
33
- >>> model = dfm.DFM()
34
- >>> model.load_config('config/default.yaml')
32
+ >>> # Step 1: Load and preprocess data
33
+ >>> df = pl.read_csv('data/sample_data.csv')
34
+ >>> df_processed = df.select([col for col in df.columns if col != 'date'])
35
35
  >>>
36
- >>> # Create transformer (user must provide)
37
- >>> transformer = ColumnTransformer([...]) # User-defined sktime transformer
36
+ >>> # Step 2: Create DataModule
37
+ >>> dm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
38
+ >>> dm.setup()
38
39
  >>>
39
- >>> # Create DataModule
40
- >>> data_module = DFMDataModule(config=model.config, transformer=transformer, data_path='data/sample_data.csv')
41
- >>> data_module.setup()
40
+ >>> # Step 3: Create model and load config
41
+ >>> model = DFM()
42
+ >>> model.load_config('config/default.yaml')
42
43
  >>>
43
- >>> # Train
44
- >>> model.train(data_module, max_iter=100)
44
+ >>> # Step 4: Create trainer and fit (standard Lightning pattern)
45
+ >>> trainer = DFMTrainer(max_epochs=100)
46
+ >>> trainer.fit(model, dm)
47
+ >>>
48
+ >>> # Step 5: Predict
45
49
  >>> Xf, Zf = model.predict(horizon=6)
46
50
  >>>
47
- >>> # Or use DDFM (separate class)
48
- >>> ddfm_model = dfm.DDFM(encoder_layers=[64, 32], num_factors=2)
49
- >>> ddfm_model.load_config('config/default.yaml')
51
+ >>> # Or use DDFM (same pattern)
52
+ >>> from dfm_python import DDFM, DDFMTrainer
50
53
  >>>
51
- >>> # Create DataModule for DDFM
52
- >>> data_module_ddfm = DFMDataModule(config=ddfm_model.config, transformer=transformer, data_path='data/sample_data.csv')
53
- >>> data_module_ddfm.setup()
54
+ >>> dm_ddfm = DFMDataModule(config_path='config/default.yaml', data=df_processed)
55
+ >>> dm_ddfm.setup()
54
56
  >>>
55
- >>> # Train
56
- >>> ddfm_model.train(data_module_ddfm, epochs=100)
57
+ >>> ddfm_model = DDFM(encoder_layers=[64, 32], num_factors=2)
58
+ >>> ddfm_model.load_config('config/default.yaml')
59
+ >>>
60
+ >>> trainer_ddfm = DDFMTrainer(max_epochs=100)
61
+ >>> trainer_ddfm.fit(ddfm_model, dm_ddfm)
57
62
  >>> Xf, Zf = ddfm_model.predict(horizon=6)
58
63
 
59
- Example (Low-level API - For advanced usage):
60
- >>> from dfm_python import DFM, DFMConfig, SeriesConfig
61
- >>> from dfm_python.transformations.utils import read_data # Preferred import
62
- >>> # Option 1: Load from YAML
63
- >>> config = load_config('config.yaml')
64
- >>> # Option 2: Create directly
65
- >>> config = DFMConfig(
66
- ... series=[SeriesConfig(frequency='m', transformation='lin', blocks=[1], series_id='series1')],
67
- ... block_names=['Global']
68
- ... )
69
- >>> from dfm_python.lightning import DFMDataModule
70
- >>> from sktime.transformations.compose import ColumnTransformer
71
- >>>
72
- >>> # Create transformer (user must provide)
73
- >>> transformer = ColumnTransformer([...]) # User-defined
74
- >>>
75
- >>> # Create DataModule
76
- >>> data_module = DFMDataModule(config=config, transformer=transformer, data_path='data.csv')
77
- >>> data_module.setup()
78
- >>>
79
- >>> # Fit model
80
- >>> model = DFM()
81
- >>> result = model.fit(data_module, config)
82
- >>> factors = result.Z # Extract estimated factors
64
+ Note: DFMConfig and SeriesConfig are internal implementation details.
65
+ Users should use Hydra YAML configuration files instead.
83
66
 
84
67
  For detailed documentation, see the README.md file and the tutorial notebooks/scripts.
85
68
  """
86
69
 
87
- __version__ = "0.4.0"
70
+ __version__ = "0.4.2"
88
71
 
89
72
  # ============================================================================
90
73
  # PUBLIC API DEFINITION
@@ -94,23 +77,24 @@ __version__ = "0.4.0"
94
77
  # Internal reorganization should not break these imports.
95
78
  #
96
79
  # Public API categories:
97
- # 1. Configuration: DFMConfig, SeriesConfig, BlockConfig, Params, config sources
80
+ # 1. Configuration: DFMConfig, SeriesConfig, config sources
98
81
  # 2. High-level API: DFM, DDFM, module-level convenience functions
99
- # 3. Core utilities: DFMCore, run_kf, TimeIndex, diagnostics
82
+ # 3. Core utilities: DFMLinear, TimeIndex, diagnostics
100
83
  # 4. Models: BaseFactorModel, DFMLinear, DDFM (low-level)
101
84
  # 5. Nowcasting: Nowcast, result classes, para_const
102
- # 6. Data & Results: DFMResult, transform_data
85
+ # 6. Data & Results: DFMResult
103
86
  # ============================================================================
104
87
 
105
88
  # Configuration (from config/ subpackage)
106
89
  from .config import (
107
- DFMConfig, SeriesConfig, BlockConfig, Params, DEFAULT_GLOBAL_BLOCK_NAME,
90
+ DEFAULT_BLOCK_NAME,
108
91
  ConfigSource, YamlSource, DictSource, HydraSource,
109
92
  MergedConfigSource, make_config_source,
110
93
  )
94
+ # Internal imports (for backward compatibility, but not recommended)
95
+ from .config import DFMConfig, SeriesConfig # Internal use only
111
96
 
112
97
  # Data utilities
113
- # Note: transform_data and DFMScaler have been removed - users must provide their own sktime transformers to DFMDataModule
114
98
 
115
99
  # Results
116
100
  from .config.results import DFMResult, DDFMResult, BaseResult
@@ -118,27 +102,15 @@ from .config.results import DFMResult, DDFMResult, BaseResult
118
102
  # Utilities (from utils/ subpackage)
119
103
  from .utils.diagnostics import diagnose_series, print_series_diagnosis
120
104
  from .utils.time import calculate_rmse
121
- # DFMCore is an alias for DFMLinear (backward compatibility)
122
- from .models.dfm import DFMLinear
123
- DFMCore = DFMLinear
124
-
125
- # PyTorch Lightning modules (recommended)
126
- try:
127
- from .lightning import (
128
- DFMLightningModule,
129
- DDFMLightningModule,
130
- DFMDataModule,
131
- KalmanFilter, # New module class
132
- EMAlgorithm, # New module class
133
- )
134
- _has_lightning = True
135
- except ImportError:
136
- _has_lightning = False
137
- DFMLightningModule = None # type: ignore
138
- DDFMLightningModule = None # type: ignore
139
- DFMDataModule = None # type: ignore
140
- KalmanFilter = None # type: ignore
141
- EMAlgorithm = None # type: ignore
105
+
106
+ # PyTorch Lightning modules (mandatory dependency)
107
+ # Users can import these directly from dfm_python
108
+ from .lightning import (
109
+ DFMDataModule,
110
+ DFMDataset, # Dataset class (usually not needed directly)
111
+ KalmanFilter, # Module class
112
+ EMAlgorithm, # Module class
113
+ )
142
114
 
143
115
  # Nowcasting (from nowcast/ subpackage)
144
116
  from .nowcast import (
@@ -154,83 +126,47 @@ from .nowcast.helpers import (
154
126
  # Model implementations
155
127
  from .models.base import BaseFactorModel
156
128
  from .models.dfm import DFMLinear, DFM
157
- from .models.dfm import (
158
- from_yaml, from_spec, from_spec_df, from_dict,
159
- load_config, load_pickle, train, predict, plot, reset, create_model
160
- )
161
- # Note: load_data has been removed - use DFMDataModule instead
162
-
163
- # DDFM high-level API and low-level model (both optional, requires PyTorch)
164
- try:
165
- from .models.ddfm import DDFM, DDFMModel
166
- from .models.ddfm import load_config_ddfm, load_data_ddfm, train_ddfm, predict_ddfm, plot_ddfm, reset_ddfm
167
- _has_ddfm = True
168
- except ImportError:
169
- _has_ddfm = False
170
- DDFM = None # type: ignore
171
- DDFMModel = None # type: ignore
172
- load_config_ddfm = None # type: ignore
173
- load_data_ddfm = None # type: ignore
174
- train_ddfm = None # type: ignore
175
- predict_ddfm = None # type: ignore
176
- plot_ddfm = None # type: ignore
177
- reset_ddfm = None # type: ignore
178
- # DDFM module-level functions removed - create DDFM() instance directly
129
+
130
+ # DDFM high-level API and low-level model (PyTorch is mandatory)
131
+ from .models.ddfm import DDFM, DDFMModel
179
132
 
180
133
  __all__ = [
181
134
  # Core classes
182
- 'DFMConfig', 'SeriesConfig', 'BlockConfig', 'Params', 'DFM', 'DFMCore', 'Nowcast',
135
+ 'DFM', 'DFMLinear', 'Nowcast',
183
136
  # Model base and implementations
184
- 'BaseFactorModel', 'DFMLinear',
137
+ 'BaseFactorModel',
185
138
  # Nowcast result classes
186
139
  'NowcastResult', 'NewsDecompResult', 'BacktestResult',
187
140
  # Constants
188
- 'DEFAULT_GLOBAL_BLOCK_NAME',
141
+ 'DEFAULT_BLOCK_NAME',
189
142
  # Config sources
190
143
  'ConfigSource', 'YamlSource', 'DictSource', 'HydraSource',
191
144
  'MergedConfigSource', 'make_config_source',
192
- # High-level API (module-level - recommended)
193
- 'load_config',
194
- 'load_pickle', 'train', 'predict', 'plot', 'reset', 'create_model',
195
- # Convenience constructors (cleaner API)
196
- 'from_yaml', 'from_spec', 'from_spec_df', 'from_dict',
197
145
  # Low-level API (functional interface - advanced usage)
198
146
  'BaseResult', 'DFMResult', 'DDFMResult', 'calculate_rmse', 'diagnose_series', 'print_series_diagnosis',
199
147
  'para_const', # Internal utility for nowcasting
200
148
  ]
201
149
 
202
- # Add DDFM high-level API and convenience functions if available
203
- if _has_ddfm:
204
- __all__.extend([
205
- 'DDFM', # High-level API class
206
- 'DDFMModel', # Low-level implementation
207
- 'load_config_ddfm', 'train_ddfm',
208
- 'predict_ddfm', 'plot_ddfm', 'reset_ddfm'
209
- # Note: load_data_ddfm has been removed - use DFMDataModule instead
210
- ])
211
-
212
- # Add Lightning modules if available
213
- if _has_lightning:
214
- __all__.extend([
215
- 'DFMLightningModule',
216
- 'DDFMLightningModule',
217
- 'DFMDataModule',
218
- 'KalmanFilter', # New module class
219
- 'EMAlgorithm', # New module class
220
- ])
221
-
222
- # Add Trainer classes if available
223
- try:
224
- from .trainer import DFMTrainer, DDFMTrainer
225
- _has_trainers = True
226
- except ImportError:
227
- _has_trainers = False
228
- DFMTrainer = None # type: ignore
229
- DDFMTrainer = None # type: ignore
230
-
231
- if _has_trainers:
232
- __all__.extend([
233
- 'DFMTrainer',
234
- 'DDFMTrainer',
235
- ])
150
+ # DDFM high-level API (PyTorch is mandatory)
151
+ __all__.extend([
152
+ 'DDFM', # High-level API class
153
+ 'DDFMModel', # Low-level implementation (used internally)
154
+ ])
155
+
156
+ # Lightning modules (mandatory dependency)
157
+ __all__.extend([
158
+ 'DFMDataModule',
159
+ 'DFMDataset', # Dataset class (usually not needed directly)
160
+ 'KalmanFilter', # Module class
161
+ 'EMAlgorithm', # Module class
162
+ ])
163
+
164
+ # Trainer classes (mandatory dependency)
165
+ from .trainer import DFMTrainer, DDFMTrainer
166
+
167
+ __all__.extend([
168
+ 'DFMTrainer',
169
+ 'DDFMTrainer',
170
+ ])
171
+
236
172
 
@@ -1,32 +1,32 @@
1
1
  """Configuration subpackage for DFM.
2
2
 
3
3
  This subpackage provides:
4
- - Schema (DFMConfig, SeriesConfig, BlockConfig, Params) in schema.py
5
- - IO (ConfigSource, YamlSource, etc.) in io.py
4
+ - Schema (DFMConfig, SeriesConfig) in schema.py
5
+ - IO (ConfigSource, YamlSource, etc.) in adapter.py
6
6
  """
7
7
 
8
8
  from .schema import (
9
- BaseModelConfig, DFMConfig, DDFMConfig, SeriesConfig, BlockConfig,
10
- DEFAULT_GLOBAL_BLOCK_NAME,
9
+ BaseModelConfig, DFMConfig, DDFMConfig, SeriesConfig,
10
+ DEFAULT_BLOCK_NAME,
11
11
  )
12
- from .params import Params, FitParams
13
- from .results import BaseResult, DFMResult, DDFMResult, DFMParams
12
+ from .results import BaseResult, DFMResult, DDFMResult, FitParams
14
13
  from .utils import validate_frequency, validate_transformation
15
- from .io import (
14
+ from .adapter import (
16
15
  ConfigSource,
17
16
  YamlSource,
18
17
  DictSource,
19
18
  HydraSource,
20
19
  MergedConfigSource,
21
20
  make_config_source,
22
- from_spec,
21
+ # Note: from_spec is in models/dfm.py, not in adapter
23
22
  # Note: Private functions (_load_config_from_dataframe, _write_series_blocks_yaml)
24
- # are available from io module but not exported as public API
23
+ # are available from adapter module but not exported as public API
25
24
  )
26
- from .structure import (
25
+ from .utils import (
27
26
  FREQUENCY_HIERARCHY,
28
27
  PERIODS_PER_YEAR,
29
28
  get_periods_per_year,
29
+ get_annual_factor,
30
30
  compute_idio_chain_lengths,
31
31
  get_tent_weights_for_pair,
32
32
  generate_tent_weights,
@@ -37,22 +37,22 @@ from .structure import (
37
37
 
38
38
  __all__ = [
39
39
  # Schema
40
- 'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'SeriesConfig', 'BlockConfig',
41
- 'DEFAULT_GLOBAL_BLOCK_NAME',
42
- # Parameters
43
- 'Params', 'FitParams',
40
+ 'BaseModelConfig', 'DFMConfig', 'DDFMConfig', 'SeriesConfig',
41
+ 'DEFAULT_BLOCK_NAME',
42
+ # Parameter overrides
43
+ 'FitParams',
44
44
  # Results
45
- 'BaseResult', 'DFMResult', 'DDFMResult', 'DFMParams',
45
+ 'BaseResult', 'DFMResult', 'DDFMResult',
46
46
  # Utilities
47
47
  'validate_frequency', 'validate_transformation',
48
48
  # IO
49
49
  'ConfigSource', 'YamlSource', 'DictSource',
50
50
  'HydraSource', 'MergedConfigSource', 'make_config_source',
51
- 'from_spec',
52
- # Structure utilities
51
+ # Frequency and aggregation utilities
53
52
  'FREQUENCY_HIERARCHY',
54
53
  'PERIODS_PER_YEAR',
55
54
  'get_periods_per_year',
55
+ 'get_annual_factor',
56
56
  'compute_idio_chain_lengths',
57
57
  'get_tent_weights_for_pair',
58
58
  'generate_tent_weights',
@@ -60,6 +60,6 @@ __all__ = [
60
60
  'get_aggregation_structure',
61
61
  'group_series_by_frequency',
62
62
  # Note: Private functions (_load_config_from_dataframe, _write_series_blocks_yaml)
63
- # are available from io module but not exported as public API
63
+ # are available from adapter module but not exported as public API
64
64
  ]
65
65