@@ -60,6 +60,9 @@ class BayesianDynamicFactor(PyMCStateSpace):
60
60
The type of Kalman Filter to use. Options are "standard", "single", "univariate", "steady_state",
61
61
and "cholesky". See the docs for kalman filters for more details.
62
62
63
+ measurement_error: bool, default True
64
+ If true, a measurement error term is added to the model.
65
+
63
66
verbose: bool, default True
64
67
If true, a message will be logged to the terminal explaining the variable names, dimensions, and supports.
65
68
@@ -100,7 +103,7 @@ class BayesianDynamicFactor(PyMCStateSpace):
100
103
factors. Careful prior specification is typically required for good estimation.
101
104
102
105
Currently, the implementation assumes same factor order for all the factors,
103
- does not yet support measurement error, exogenous variables and joint (VAR) error modeling.
106
+ does not yet support exogenous variables and joint (VAR) error modeling.
104
107
105
108
Examples
106
109
--------
@@ -161,6 +164,7 @@ def __init__(
161
164
error_var : bool = False ,
162
165
error_cov_type : str = "diagonal" ,
163
166
filter_type : str = "standard" ,
167
+ measurement_error : bool = False ,
164
168
verbose : bool = True ,
165
169
):
166
170
if k_endog is None and endog_names is None :
@@ -174,6 +178,7 @@ def __init__(
174
178
raise NotImplementedError (
175
179
"Joint error modeling (error_var=True) is not yet implemented."
176
180
)
181
+
177
182
if exog is not None :
178
183
raise NotImplementedError ("Exogenous variables (exog) are not yet implemented." )
179
184
@@ -185,7 +190,6 @@ def __init__(
185
190
self .error_var = error_var
186
191
self .error_cov_type = error_cov_type
187
192
self .exog = exog
188
- # TODO add measurement error support
189
193
# TODO add exogenous variables support?
190
194
191
195
# Determine the dimension for the latent factor states.
@@ -213,7 +217,7 @@ def __init__(
213
217
k_posdef = k_posdef ,
214
218
filter_type = filter_type ,
215
219
verbose = verbose ,
216
- measurement_error = False ,
220
+ measurement_error = measurement_error ,
217
221
)
218
222
219
223
@property
@@ -226,6 +230,7 @@ def param_names(self):
226
230
"factor_sigma" ,
227
231
"error_ar" ,
228
232
"error_sigma" ,
233
+ "sigma_obs" ,
229
234
]
230
235
231
236
# Handle cases where parameters should be excluded based on model settings
@@ -236,6 +241,8 @@ def param_names(self):
236
241
if self .error_cov_type == "unstructured" :
237
242
names .remove ("error_sigma" )
238
243
names .append ("error_cov" )
244
+ if not self .measurement_error :
245
+ names .remove ("sigma_obs" )
239
246
240
247
return names
241
248
@@ -274,6 +281,10 @@ def param_info(self) -> dict[str, dict[str, Any]]:
274
281
"shape" : (self .k_endog , self .k_endog ),
275
282
"constraints" : "Positive Semi-definite" ,
276
283
},
284
+ "sigma_obs" : {
285
+ "shape" : (self .k_endog ,),
286
+ "constraints" : "Positive Semi-definite" ,
287
+ },
277
288
}
278
289
279
290
for name in self .param_names :
@@ -361,7 +372,8 @@ def param_dims(self):
361
372
coord_map ["error_sigma" ] = (OBS_STATE_DIM ,)
362
373
if self .error_cov_type == "unstructured" :
363
374
coord_map ["error_sigma" ] = (OBS_STATE_DIM , OBS_STATE_AUX_DIM )
364
-
375
+ if self .measurement_error :
376
+ coord_map ["sigma_obs" ] = (OBS_STATE_DIM ,)
365
377
return coord_map
366
378
367
379
def make_symbolic_graph (self ):
@@ -456,4 +468,11 @@ def build_ar_block_matrix(ar_coeffs):
456
468
)
457
469
458
470
# Observation covariance matrix
459
- self .ssm ["obs_cov" , :, :] = 0.0
471
+ if self .measurement_error :
472
+ sigma_obs = self .make_and_register_variable (
473
+ "sigma_obs" , shape = (self .k_endog ,), dtype = floatX
474
+ )
475
+ self .ssm ["obs_cov" , :, :] = pt .diag (sigma_obs )
476
+ else :
477
+ # If measurement error is not used, set obs_cov to zero
478
+ self .ssm ["obs_cov" , :, :] = 0.0
0 commit comments