|
10 | 10 | from orbit.constants.constants import ( |
11 | 11 | DEFAULT_REGRESSOR_SIGN, |
12 | 12 | DEFAULT_REGRESSOR_BETA, |
13 | | - DEFAULT_REGRESSOR_SIGMA |
| 13 | + DEFAULT_REGRESSOR_SIGMA, |
| 14 | + COEFFICIENT_DF_COLS, |
| 15 | + PredictMethod |
14 | 16 | ) |
15 | 17 | from orbit.exceptions import ( |
16 | 18 | PredictionException, |
@@ -362,6 +364,95 @@ def _set_model_param_names(self): |
362 | 364 | self.model_param_names += [ |
363 | 365 | lgt.RegressionStanSamplingParameters.REGULAR_REGRESSOR_BETA.value] |
364 | 366 |
|
| 367 | + @staticmethod |
| 368 | + def _concat_regression_coefs(pr_beta=None, rr_beta=None): |
| 369 | + """Concatenates regression posterior matrix |
| 370 | +
|
| 371 | + In the case that `pr_beta` or `rr_beta` is a 1d tensor, transform to 2d tensor and |
| 372 | + concatenate. |
| 373 | +
|
| 374 | + Args |
| 375 | + ---- |
| 376 | + pr_beta : torch.tensor |
| 377 | + postive-value constrainted regression betas |
| 378 | + rr_beta : torch.tensor |
| 379 | + regular regression betas |
| 380 | +
|
| 381 | + Returns |
| 382 | + ------- |
| 383 | + torch.tensor |
| 384 | + concatenated 2d tensor of shape (1, len(rr_beta) + len(pr_beta)) |
| 385 | +
|
| 386 | + """ |
| 387 | + regressor_beta = None |
| 388 | + if pr_beta is not None and rr_beta is not None: |
| 389 | + pr_beta = pr_beta if len(pr_beta.shape) == 2 else pr_beta.reshape(1, -1) |
| 390 | + rr_beta = rr_beta if len(rr_beta.shape) == 2 else rr_beta.reshape(1, -1) |
| 391 | + regressor_beta = torch.cat((pr_beta, rr_beta), dim=1) |
| 392 | + elif pr_beta is not None: |
| 393 | + regressor_beta = pr_beta |
| 394 | + elif rr_beta is not None: |
| 395 | + regressor_beta = rr_beta |
| 396 | + |
| 397 | + return regressor_beta |
| 398 | + |
| 399 | + def get_regression_coefs(self, aggregation_method='mean'): |
| 400 | + """Return DataFrame regression coefficients |
| 401 | +
|
| 402 | + Args |
| 403 | + ---- |
| 404 | + aggregation_method : str |
| 405 | + any PredictMethod except `full` |
| 406 | + """ |
| 407 | + def _validate_args(): |
| 408 | + valid_args = set([x.value for x in PredictMethod]) |
| 409 | + valid_args = valid_args - set([PredictMethod.FULL_SAMPLING.value]) |
| 410 | + |
| 411 | + if aggregation_method not in valid_args: |
| 412 | + raise IllegalArgument("aggregation_method must be one of {}".format(valid_args)) |
| 413 | + |
| 414 | + # init dataframe |
| 415 | + reg_df = pd.DataFrame() |
| 416 | + |
| 417 | + # end if no regressors |
| 418 | + if self.num_of_regular_regressors + self.num_of_positive_regressors == 0: |
| 419 | + return reg_df |
| 420 | + |
| 421 | + _validate_args() |
| 422 | + |
| 423 | + pr_beta = self.aggregated_posteriors\ |
| 424 | + .get(aggregation_method)\ |
| 425 | + .get(lgt.RegressionStanSamplingParameters.POSITIVE_REGRESSOR_BETA.value) |
| 426 | + |
| 427 | + rr_beta = self.aggregated_posteriors\ |
| 428 | + .get(aggregation_method)\ |
| 429 | + .get(lgt.RegressionStanSamplingParameters.REGULAR_REGRESSOR_BETA.value) |
| 430 | + |
| 431 | + # because `_conccat_regression_coefs` operates on torch tensors |
| 432 | + pr_beta = torch.from_numpy(pr_beta) if pr_beta is not None else pr_beta |
| 433 | + rr_beta = torch.from_numpy(rr_beta) if rr_beta is not None else rr_beta |
| 434 | + |
| 435 | + regressor_betas = self._concat_regression_coefs(pr_beta, rr_beta) |
| 436 | + |
| 437 | + # get column names |
| 438 | + pr_cols = self.positive_regressor_col |
| 439 | + rr_cols = self.regular_regressor_col |
| 440 | + |
| 441 | + # note ordering here is not the same as `self.regressor_cols` because positive |
| 442 | + # and negative do not have to be grouped on input |
| 443 | + regressor_cols = pr_cols + rr_cols |
| 444 | + |
| 445 | + # same note |
| 446 | + regressor_signs \ |
| 447 | + = ["Positive"] * self.num_of_positive_regressors \ |
| 448 | + + ["Regular"] * self.num_of_regular_regressors |
| 449 | + |
| 450 | + reg_df[COEFFICIENT_DF_COLS.REGRESSOR] = regressor_cols |
| 451 | + reg_df[COEFFICIENT_DF_COLS.REGRESSOR_SIGN] = regressor_signs |
| 452 | + reg_df[COEFFICIENT_DF_COLS.COEFFICIENT] = regressor_betas.flatten() |
| 453 | + |
| 454 | + return reg_df |
| 455 | + |
365 | 456 | def _predict(self, df=None, include_error=False, decompose=False): |
366 | 457 | """Vectorized version of prediction math""" |
367 | 458 |
|
@@ -407,16 +498,7 @@ def _predict(self, df=None, include_error=False, decompose=False): |
407 | 498 | # regression components |
408 | 499 | pr_beta = model.get(lgt.RegressionStanSamplingParameters.POSITIVE_REGRESSOR_BETA.value) |
409 | 500 | rr_beta = model.get(lgt.RegressionStanSamplingParameters.REGULAR_REGRESSOR_BETA.value) |
410 | | - regressor_beta = None |
411 | | - if pr_beta is not None and rr_beta is not None: |
412 | | - pr_beta = pr_beta if len(pr_beta.shape) == 2 else pr_beta.reshape(1, -1) |
413 | | - rr_beta = rr_beta if len(rr_beta.shape) == 2 else rr_beta.reshape(1, -1) |
414 | | - regressor_beta = torch.cat((pr_beta, rr_beta), dim=1) |
415 | | - elif pr_beta is not None: |
416 | | - regressor_beta = pr_beta |
417 | | - elif rr_beta is not None: |
418 | | - regressor_beta = rr_beta |
419 | | - |
| 501 | + regressor_beta = self._concat_regression_coefs(pr_beta, rr_beta) |
420 | 502 |
|
421 | 503 | ################################################################ |
422 | 504 | # Prediction Attributes |
|
0 commit comments