class_docstr: This class enables Greykite based anomaly detection algorithms.
      It takes a ``forecast_config`` and ``ad_config`` (see Parameters) and builds a detector which
      uses the forecast as baseline.
  
      The fit consists of following stages:
  
      - Fit a forecast model using the ``forecast_config`` passed
      - Fit a volatility model using
          `~greykite.algo.uncertainty.conditional.conf_interval.conf_interval`
          to optimize over
  
          -- ``volatility_features_list``
          -- ``coverage_grid``
  
          specified in ``ad_config`` passed.
  
  Parameters
  ----------
  ad_config: `~greykite.detection.detector.config.ADConfig` or None, default None
      Config object for anomaly detection to use.
  forecast_config : `~greykite.framework.templates.model_templates.ForecastConfig` or None, default None
      Config object for forecast to use.
  reward : See docstring for
      `~greykite.detection.detector.detector.Detector`
  
  Attributes
  ----------
  anomaly_percent_dict : `dict` or None,
      See attributes of `~greykite.detection.detector.detector.Detector`
  forecast_result : `~greykite.framework.pipeline.pipeline.ForecastResult` or None
      See class:`~greykite.framework.pipeline.pipeline.ForecastResult`
      for details.
  forecast_estimator : `~greykite.sklearn.estimator.base_forecast_estimator.BaseForecastEstimator` or None
      See class: `~greykite.sklearn.estimator.base_forecast_estimator.BaseForecastEstimator`
      for more details.
  ci_model : `dict`
      This is the fitted volatility model which is the returned dictionary from
      `greykite.algo.uncertainty.conditional.conf_interval`.
  fit_info : `dict` or None
      See attributes of `~greykite.detection.detector.detector.Detector`.
  anomaly_df : `pandas.DataFrame` or None
      A dataframe which includes the start and end times of observed anomalies.
  fit_data : `~greykite.detection.detector.data.DetectorData` or None
      The data used in the `fit` method.
class_docstr_tok: ["This","class","enables","Greykite","based","anomaly","detection","algorithms",".","It","takes","a","``","forecast_config","``","and","``","ad_config","``","(","see","Parameters",")","and","builds","a","detector","which","uses","the","forecast","as","baseline",".","The","fit","consists","of","following","stages",":","-","Fit","a","forecast","model","using","the","``","forecast_config","``","passed","-","Fit","a","volatility","model","using","`","~greykite.algo.uncertainty.conditional.conf_interval.conf_interval","`","to","optimize","over","--","``","volatility_features_list","``","--","``","coverage_grid","``","specified","in","``","ad_config","``","passed",".","Parameters","--","--","--","--","--","ad_config",":","`","~greykite.detection.detector.config.ADConfig","`","or","None",",","default","None","Config","object","for","anomaly","detection","to","use",".","forecast_config",":","`","~greykite.framework.templates.model_templates.ForecastConfig","`","or","None",",","default","None","Config","object","for","forecast","to","use",".","reward",":","See","docstring","for","`","~greykite.detection.detector.detector.Detector","`","Attributes","--","--","--","--","--","anomaly_percent_dict",":","`","dict","`","or","None",",","See","attributes","of","`","~greykite.detection.detector.detector.Detector","`","forecast_result",":","`","~greykite.framework.pipeline.pipeline.ForecastResult","`","or","None","See","class",":","`","~greykite.framework.pipeline.pipeline.ForecastResult","`","for","details",".","forecast_estimator",":","`","~greykite.sklearn.estimator.base_forecast_estimator.BaseForecastEstimator","`","or","None","See","class",":","`","~greykite.sklearn.estimator.base_forecast_estimator.BaseForecastEstimator","`","for","more","details",".","ci_model",":","`","dict","`","This","is","the","fitted","volatility","model","which","is","the","returned","dictionary","from","`","greykite.algo.uncertainty.conditional.conf_interval","`",".","fit_info",":","`","dict","`","or","None","See","attributes","of","`","~greykite.detection.detector.detector.Detector","`",".","anomaly_df",":","`","pandas.DataFrame","`","or","None","A","dataframe","which","includes","the","start","and","end","times","of","observed","anomalies",".","fit_data",":","`","~greykite.detection.detector.data.DetectorData","`","or","None","The","data","used","in","the","`","fit","`","method","."]
docstr: Predicts anomalies assuming the parameters:
  
      - ``volatility_features``
      - ``coverage``
  
  are passed. This will enable optimization over these parameters
  in the `fit` phase.
  
  Parameters
  ----------
  param : `dict`
      The parameter to optimize over if desired.
  data : `~greykite.detection.detector.data.DetectorData`
      The input data which needs to include the input timeseries in ``df``
      attribute. We assume df includes minimally these two columns:
  
          - ``TIME_COL``
          - ``VALUE_COL``
  
      and if labels are also available in this datasets we expect the labels
      to be available in ``ANOMALY_COL``
  phase : `str`, default ``PHASE_PREDICT``
      If ``PHASE_PREDICT`` the baseline data will be generated and otherwise we
      assume we are in fitting phase and will extract the baseline from the
      fitted model.
  
  Returns
  -------
  cal_result: A calculation result from the optimizer.
  See `~greykite.detection.detector.optimizer.CalcResult`
docstr_tok: ["Predicts","anomalies","assuming","the","parameters",":","-","``","volatility_features","``","-","``","coverage","``","are","passed",".","This","will","enable","optimization","over","these","parameters","in","the","`","fit","`","phase",".","Parameters","--","--","--","--","--","param",":","`","dict","`","The","parameter","to","optimize","over","if","desired",".","data",":","`","~greykite.detection.detector.data.DetectorData","`","The","input","data","which","needs","to","include","the","input","timeseries","in","``","df","``","attribute",".","We","assume","df","includes","minimally","these","two","columns",":","-","``","TIME_COL","``","-","``","VALUE_COL","``","and","if","labels","are","also","available","in","this","datasets","we","expect","the","labels","to","be","available","in","``","ANOMALY_COL","``","phase",":","`","str","`",",","default","``","PHASE_PREDICT","``","If","``","PHASE_PREDICT","``","the","baseline","data","will","be","generated","and","otherwise","we","assume","we","are","in","fitting","phase","and","will","extract","the","baseline","from","the","fitted","model",".","Returns","--","--","--","-","cal_result",":","A","calculation","result","from","the","optimizer",".","See","`","~greykite.detection.detector.optimizer.CalcResult","`"]
code: def calc_with_param(self, param, data=None, phase=PHASE_PREDICT):
      """Predicts anomalies assuming the parameters:
  
          - ``volatility_features``
          - ``coverage``
  
      are passed. This will enable optimization over these parameters
      in the `fit` phase.
  
      Parameters
      ----------
      param : `dict`
          The parameter to optimize over if desired.
      data : `~greykite.detection.detector.data.DetectorData`
          The input data which needs to include the input timeseries in ``df``
          attribute. We assume df includes minimally these two columns:
  
              - ``TIME_COL``
              - ``VALUE_COL``
  
          and if labels are also available in this datasets we expect the labels
          to be available in ``ANOMALY_COL``
      phase : `str`, default ``PHASE_PREDICT``
          If ``PHASE_PREDICT`` the baseline data will be generated and otherwise we
          assume we are in fitting phase and will extract the baseline from the
          fitted model.
  
      Returns
      -------
      cal_result: A calculation result from the optimizer.
      See `~greykite.detection.detector.optimizer.CalcResult`
      """
      df = data.df.copy()
      model = self.forecast_estimator
      trained_model = model.model_dict
  
      if phase == PHASE_PREDICT:
          # `forecast_pred_df` has the forecasted values.
          forecast_pred_df = model.predict(X=df)
          x_mat = model.forecast_x_mat
          # Extracts only the time column and forecast column.
          forecast_pred_df = forecast_pred_df[[TIME_COL, PREDICTED_COL]]
      else:
          x_mat = trained_model["x_mat"]
          forecast_pred_df = trained_model["fitted_df"].copy()
          # Extracts only the time column and forecast column.
          # Forecasts are in the original `value_col` in fitted data.
          forecast_pred_df = forecast_pred_df[[TIME_COL, VALUE_COL]]
          forecast_pred_df.columns = [TIME_COL, PREDICTED_COL]
          # Asserts that the returned dataframe has the correct size.
          assert len(forecast_pred_df) == len(df), (
              f"length of `forecast_pred_df`: {len(forecast_pred_df)},"
              f" must be same as length of `df`: {len(df)}"
          )
  
      volatility_df = pd.merge(df, forecast_pred_df, on=TIME_COL)
      assert len(volatility_df) == len(
          df
      ), "length of `volatility_df` must be same `df`"
  
      # Adds time features
      volatility_df = add_time_features_df(
          df=volatility_df,
          time_col=TIME_COL,
          conti_year_origin=trained_model["origin_for_time_vars"],
      )
  
      # Adds daily events (e.g. holidays)
      # if daily event data are given, we add them to temporal features data
      # `date_col` below is used to join with `daily_events` data given
      # in `daily_event_df_dict`.
      # Note: events must be provided for both train and forecast time range.
      daily_event_df_dict = trained_model["daily_event_df_dict"]
      if daily_event_df_dict is not None:
          daily_event_neighbor_impact = trained_model[
              "daily_event_neighbor_impact"
          ]
          volatility_df = add_daily_events(
              df=volatility_df,
              event_df_dict=daily_event_df_dict,
              date_col="date",
              neighbor_impact=daily_event_neighbor_impact,
          )
  
      coverage = param.get("coverage", None)
      volatility_features = param.get(
          "volatility_features", []
      )  # volatility features can be empty
      ape = param.get(
          ElementwiseEvaluationMetricEnum.AbsolutePercentError.get_metric_name(),
          None,
      )
      sape = param.get(
          ElementwiseEvaluationMetricEnum.SymmetricAbsolutePercentError.get_metric_name(),
          None,
      )
      sigma_scaler = trained_model["sigma_scaler"]
      h_mat = trained_model["h_mat"]
      x_mean = trained_model["x_mean"]
      if (
          self.ad_config.variance_scaling is False
          or self.ad_config.variance_scaling is None
      ):
          # Enables default variance scaling.
          sigma_scaler = None
          h_mat = None
  
      if phase == "fit":
          alpha = 1 - coverage
          q_lower = alpha / 2.0
          q_upper = 1 - q_lower
          quantiles = (q_lower, q_upper)
  
          # Residual column is calculated based on the adjusted values so that the anomalies and outliers
          # do not impact the training of the volatility model.
          volatility_df[RESIDUAL_COL] = (
              volatility_df[f"adjusted_{VALUE_COL}"]
              - volatility_df[PREDICTED_COL]
          )
          ci_model = conf_interval(
              df=volatility_df,
              distribution_col=RESIDUAL_COL,
              offset_col=PREDICTED_COL,
              conditional_cols=volatility_features,
              quantiles=quantiles,
              sigma_scaler=sigma_scaler,
              h_mat=h_mat,
              x_mean=x_mean,
              min_admissible_value=self.ad_config.min_admissible_value,
              max_admissible_value=self.ad_config.max_admissible_value,
          )
      else:
          ci_model = self.fit_info["best_calc_result"].model
  
      # Calculates the prediction intervals using the fitted `ci_model`.
      # Note that if there is no variance scaling (since variance scaling only applies to ridge / linear regression),
      # `ci_model` has contained this information since both `sigma_scaler` and `h_mat` were set to `None`.
      # In this case, the `predict_ci` function behaves the same as `x_mat` is not passed.
      # Also note that the default behavior in greykite is to scale the variance.
      ci_df = predict_ci(
          new_df=volatility_df, ci_model=ci_model, x_mat=x_mat
      )
      # Adds the z score column.
      ci_df[Z_SCORE_COL] = (
          ci_df[VALUE_COL] - ci_df[PREDICTED_COL]
      ) / ci_df[ERR_STD_COL]
  
      cols = [
          PREDICTED_COL,
          QUANTILE_SUMMARY_COL,
          ERR_STD_COL,
          Z_SCORE_COL,
      ]
      pred_df = pd.concat([df, ci_df[cols]], axis=1)
      pred_df[PREDICTED_LOWER_COL] = pred_df[QUANTILE_SUMMARY_COL].map(
          lambda x: x[0]
      )
      pred_df[PREDICTED_UPPER_COL] = pred_df[QUANTILE_SUMMARY_COL].map(
          lambda x: x[1]
      )
  
      # Since, we like to return the observed values in `ACTUAL_COL`,
      # the column `ACTUAL_COL` is added and it is set to be equal to
      # the `VALUE_COL` which includes the observed values.
      pred_df[ACTUAL_COL] = pred_df[VALUE_COL]
  
      # Anomaly is declared when the actual is outside the confidence interval.
      y_pred = (pred_df[ACTUAL_COL] < pred_df[PREDICTED_LOWER_COL]) | (
          pred_df[ACTUAL_COL] > pred_df[PREDICTED_UPPER_COL]
      )
  
      # Adds Absolute Percent Error (APE) threshold check if ape is not None.
      if ape is not None:
          metric = ElementwiseEvaluationMetricEnum.AbsolutePercentError
          pred_df[metric.get_metric_name()] = pred_df.apply(
              lambda row: metric.get_metric_func()(
                  row[ACTUAL_COL], row[PREDICTED_COL]
              ),
              axis=1,
          )
          y_pred = y_pred & (pred_df[metric.get_metric_name()] > ape)
  
      # Adds Symmetric Absolute Percent Error (SAPE) threshold check if sape is not None.
      if sape is not None:
          metric = (
              ElementwiseEvaluationMetricEnum.SymmetricAbsolutePercentError
          )
          pred_df[metric.get_metric_name()] = pred_df.apply(
              lambda row: metric.get_metric_func()(
                  row[ACTUAL_COL], row[PREDICTED_COL]
              ),
              axis=1,
          )
          y_pred = y_pred & (pred_df[metric.get_metric_name()] > sape)
  
      pred_df[PREDICTED_ANOMALY_COL] = y_pred
  
      # Only subset the columns needed / prescribed.
      pred_df = pred_df[DETECTOR_PREDICT_COLS]
      if ANOMALY_COL in df.columns:
          pred_df[ANOMALY_COL] = df[ANOMALY_COL]
      else:
          pred_df[ANOMALY_COL] = None
      data.y_pred = y_pred
      data.pred_df = pred_df
  
      return CalcResult(data=data, model=ci_model)
  
imports: from copy import deepcopy
  import numpy
  import pandas
  from greykite.algo.uncertainty.conditional.conf_interval import conf_interval
  from greykite.algo.uncertainty.conditional.conf_interval import predict_ci
  from greykite.common.constants import ACTUAL_COL
  from greykite.common.constants import ANOMALY_COL
  from greykite.common.constants import END_TIME_COL
  from greykite.common.constants import ERR_STD_COL
  from greykite.common.constants import PREDICTED_ANOMALY_COL
  from greykite.common.constants import PREDICTED_COL
  from greykite.common.constants import PREDICTED_LOWER_COL
  from greykite.common.constants import PREDICTED_UPPER_COL
  from greykite.common.constants import QUANTILE_SUMMARY_COL
  from greykite.common.constants import RESIDUAL_COL
  from greykite.common.constants import START_TIME_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.constants import VALUE_COL
  from greykite.common.evaluation import ElementwiseEvaluationMetricEnum
  from greykite.common.features.adjust_anomalous_data import adjust_anomalous_data
  from greykite.common.features.timeseries_features import add_daily_events
  from greykite.common.features.timeseries_features import add_time_features_df
  from greykite.common.logging import LoggingLevelEnum
  from greykite.common.logging import log_message
  from greykite.common.time_properties import describe_timeseries
  from greykite.common.time_properties import get_canonical_data
  from greykite.common.time_properties import infer_freq
  from greykite.detection.detector.ad_utils import add_new_params_to_records
  from greykite.detection.detector.ad_utils import get_anomaly_df
  from greykite.detection.detector.ad_utils import get_anomaly_df_from_outliers
  from greykite.detection.detector.ad_utils import get_canonical_anomaly_df
  from greykite.detection.detector.config import ADConfig
  from greykite.detection.detector.config_to_reward import config_to_reward
  from greykite.detection.detector.constants import DEFAULT_COVERAGE_GRID
  from greykite.detection.detector.constants import PHASE_PREDICT
  from greykite.detection.detector.constants import Z_SCORE_COL
  from greykite.detection.detector.detector import Detector
  from greykite.detection.detector.optimizer import CalcResult
  from greykite.framework.templates.autogen.forecast_config import ForecastConfig
  from greykite.framework.templates.autogen.forecast_config import MetadataParam
  from greykite.framework.templates.forecaster import Forecaster
label_desc: Use image node_id 3 for calling the GreykiteDetector obj's underlying member method code with example usage: obj.calc_with_param(param, data, phase) and returns: CalcResult