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: This function combines anomalies information that may exist in various places
  and combine them into a consistent `anomaly_df`: a point will be an anomaly if it appears in
  ANY of the given inputs.
  
  1. As `ANOMALY_COL` column in the input fit_data (`fit_data.df`)
  2. As a vector in the input fit_data (`fit_data.y_true`)
  3. As a separate dataframe in the input fit_data (`fit_data.anomaly_df`)
  4. As a separate dataframe in the `metadata_param` in the `forecast_config`.
  
  It then updates the anomaly information to be the final one across various inputs.
  
  Parameters
  ----------
  fit_data : `~greykite.detection.detector.fit_data.DetectorData` or None, default None
      The input fit_data to the `fit` method.
  freq : `str`
      The frequency of the input fit_data.
  
  Returns
  -------
  fit_data : `~greykite.detection.detector.data.DetectorData`
      The updated fit_data which includes the merged anomaly information.
docstr_tok: ["This","function","combines","anomalies","information","that","may","exist","in","various","places","and","combine","them","into","a","consistent","`","anomaly_df","`",":","a","point","will","be","an","anomaly","if","it","appears","in","ANY","of","the","given","inputs",".","1",".","As","`","ANOMALY_COL","`","column","in","the","input","fit_data","(","`","fit_data.df","`",")","2",".","As","a","vector","in","the","input","fit_data","(","`","fit_data.y_true","`",")","3",".","As","a","separate","dataframe","in","the","input","fit_data","(","`","fit_data.anomaly_df","`",")","4",".","As","a","separate","dataframe","in","the","`","metadata_param","`","in","the","`","forecast_config","`",".","It","then","updates","the","anomaly","information","to","be","the","final","one","across","various","inputs",".","Parameters","--","--","--","--","--","fit_data",":","`","~greykite.detection.detector.fit_data.DetectorData","`","or","None",",","default","None","The","input","fit_data","to","the","`","fit","`","method",".","freq",":","`","str","`","The","frequency","of","the","input","fit_data",".","Returns","--","--","--","-","fit_data",":","`","~greykite.detection.detector.data.DetectorData","`","The","updated","fit_data","which","includes","the","merged","anomaly","information","."]
code: def merge_anomaly_info(self, fit_data, freq):
      """This function combines anomalies information that may exist in various places
      and combine them into a consistent `anomaly_df`: a point will be an anomaly if it appears in
      ANY of the given inputs.
  
      1. As `ANOMALY_COL` column in the input fit_data (`fit_data.df`)
      2. As a vector in the input fit_data (`fit_data.y_true`)
      3. As a separate dataframe in the input fit_data (`fit_data.anomaly_df`)
      4. As a separate dataframe in the `metadata_param` in the `forecast_config`.
  
      It then updates the anomaly information to be the final one across various inputs.
  
      Parameters
      ----------
      fit_data : `~greykite.detection.detector.fit_data.DetectorData` or None, default None
          The input fit_data to the `fit` method.
      freq : `str`
          The frequency of the input fit_data.
  
      Returns
      -------
      fit_data : `~greykite.detection.detector.data.DetectorData`
          The updated fit_data which includes the merged anomaly information.
      """
      df = fit_data.df.copy()
      merged_anomaly_df = pd.DataFrame()
  
      # Adds anomalies from `fit_data.df`.
      if ANOMALY_COL in df.columns:
          anomaly_df = get_anomaly_df(
              df=df, time_col=TIME_COL, anomaly_col=ANOMALY_COL
          )
          merged_anomaly_df = pd.concat([merged_anomaly_df, anomaly_df])
  
      # Adds anomalies from `fit_data.y_true`.
      if fit_data.y_true is not None:
          assert len(fit_data.y_true) == len(
              df
          ), f"length of `y_true`: {len(fit_data.y_true)}, must be same as length of `df`: {len(df)}"
          # Builds a temporary df to be used in `get_anomaly_df`.
          temp_df = pd.DataFrame(
              {TIME_COL: df[TIME_COL], ANOMALY_COL: fit_data.y_true}
          )
          anomaly_df = get_anomaly_df(
              df=temp_df, time_col=TIME_COL, anomaly_col=ANOMALY_COL
          )
          merged_anomaly_df = pd.concat([merged_anomaly_df, anomaly_df])
  
      # Adds anomalies from `fit_data.anomaly_df`.
      if fit_data.anomaly_df is not None:
          fit_data.anomaly_df = fit_data.anomaly_df[
              [START_TIME_COL, END_TIME_COL]
          ]
          merged_anomaly_df = pd.concat(
              [merged_anomaly_df, fit_data.anomaly_df]
          )
  
      # Adds anomalies from `metadata_param` in `forecast_config`.
      metadata_param = self.forecast_config.metadata_param
      if (metadata_param is not None) and (
          metadata_param.anomaly_info is not None
      ):
          anomaly_df = metadata_param.anomaly_info.get(
              "anomaly_df", None
          )
          if anomaly_df is not None:
              anomaly_df = anomaly_df[[START_TIME_COL, END_TIME_COL]]
          merged_anomaly_df = pd.concat([merged_anomaly_df, anomaly_df])
  
      # Input fit_data might have huge outliers which have a large impact on model fit.
      # At this step, the function identifies outliers based on z-scores
      # and constructs `anomaly_df_outliers`to save the information,
      # which is added to `merged_anomaly_df`.
      # Does 1.0 percent trimming to ensure the standard deviation and mean,
      # used in z-score calculation are robust.
      anomaly_df_outliers = get_anomaly_df_from_outliers(
          df=df,
          time_col=TIME_COL,
          value_col=VALUE_COL,
          freq=freq,
          trim_percent=1.0,
      )
      if not anomaly_df_outliers.empty:
          log_message(
              f"Found the following outliers: \n{anomaly_df_outliers[START_TIME_COL]}. "
              " Adding these to `anomaly_df`.",
              LoggingLevelEnum.WARNING,
          )
          merged_anomaly_df = pd.concat(
              [merged_anomaly_df, anomaly_df_outliers]
          )
  
      # Gets canonical anomaly df.
      if merged_anomaly_df.empty:
          merged_anomaly_df = None
          log_message(
              "No anomalies are provided and no outliers have been found. "
              "Setting 'anomaly_df' to None.",
              LoggingLevelEnum.WARNING,
          )
      else:
          merged_anomaly_df = get_canonical_anomaly_df(
              anomaly_df=merged_anomaly_df, freq=freq
          )
  
      # Updates `anomaly_df` in respective places.
      if merged_anomaly_df is not None:
          # Directly adjusts anomalies in input fit_data,
          # so that prediction intervals are not impacted by outliers as well
          # in `predict_with_params` during the "fit" phase.
          # Values of the anomaly locations will become none in "adjusted_{VALUE_COL}" column.
          adj_df_info = adjust_anomalous_data(
              df=df,
              time_col=TIME_COL,
              value_col=VALUE_COL,
              anomaly_df=merged_anomaly_df,
          )
          df = adj_df_info["augmented_df"]
          df[ANOMALY_COL] = df[ANOMALY_COL].astype(bool)
  
          if self.forecast_config.metadata_param is None:
              self.forecast_config.metadata_param = MetadataParam()
          if self.forecast_config.metadata_param.anomaly_info is None:
              self.forecast_config.metadata_param.anomaly_info = {
                  "value_col": VALUE_COL,
                  "anomaly_df": merged_anomaly_df,
              }
          else:
              self.forecast_config.metadata_param.anomaly_info.update(
                  {
                      "value_col": VALUE_COL,
                      "anomaly_df": merged_anomaly_df,
                  }
              )
      else:
          df[f"adjusted_{VALUE_COL}"] = df[VALUE_COL]
          df[ANOMALY_COL] = None
      fit_data.y_true = df[ANOMALY_COL]
      fit_data.df = df
      fit_data.anomaly_df = merged_anomaly_df
      self.anomaly_df = merged_anomaly_df
  
      return fit_data
  
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 4 for calling the GreykiteDetector obj's underlying member method code with example usage: obj.merge_anomaly_info(fit_data, freq) and returns: fit_data