code: def build_anomaly_percent_reward(anomaly_percent_dict):
      """This builds an reward function given an expected anomaly percent range.
      This is the expected percent of anomalies in the data by user.
      This is useful when the user does now know which points are anomalies,
      but has some idea about what percent of data are anomalies.
      The reward function constructed here will penalize for being far from the
      center of the range specified by the user (``anomaly_percent_dict["range"]``)
      and it will add an extra penalty for being outside that interval. The penalty
      is specified in``anomaly_percent_dict["penalty"]``.
  
      Parameters
      ----------
      anomaly_percent_dict : `dict` or None, default None
          If not None, a dictionary with items:
  
          - ``"range"`` : `tuple`
              We expect a tuple with two elements.
          - ``"penalty"`` : `float`
              A real number to specify the penalty of being outside the range
              specified by user. It should be typically a negative value and it
              could be set to ``float("-inf")`` to make this reward a restriction
              while using it along with other rewards.
  
          The dictionary is used to construct an reward which will be the reward in
          the optimization is no reward is passed to the ``Detector`` class below.
  
          If another reward is passed then this will be added to the passed reward.
  
          The constructed reward based on ``anomaly_percent_dict`` penalizes
          by the distance between the center of the ``"range"`` and predicted anomaly
          percent as long as the predicted is within range.
  
          For values outside the range an extra penalty given in`"penalty"`
          will be applied.
          If `"penalty"` is None, it will be set to -1.
  
          If None, the default ``DEFAULT_ANOMALY_PERCENT_DICT`` will be used.
  
      Returns
      -------
      result : `~greykite.detection.detector.reward.Reward`
          The reward which reflects the information given in the input.
      """
      min_percent = anomaly_percent_dict["range"][0]
      max_percent = anomaly_percent_dict["range"][1]
      target_percent = (min_percent + max_percent) / 2.0
  
      def reward_func(data):
          percent_anomaly = 100 * np.mean(data.y_pred)
          diff = abs(percent_anomaly - target_percent) / 100.0
          # `-diff` will be returned because we assume higher is better
          return -diff
  
      # Below intends to calculate which diffs using the above reward
      # function transalte to the `percent_anomaly` being outside the
      # specified range in `anomaly_percent_dict`
      # Considering the above `reward_func` measures the diff from the mid-point
      # of the range: we can deduce that maximum diff which still remains in
      # the range is the length of the range.
      # since the`reward_func` also divides the diff by 100, we also divide by
      # 100.
      max_acceptable_diff = (max_percent - min_percent) / (2 * 100.0)
  
      penalty = anomaly_percent_dict["penalty"]
      if penalty is None:
          penalty = -1
  
      # Below `min_unpenalized=-max_acceptable_diff` will ensure that `percent_anomaly`
      # which is outside the specified range in `anomaly_percent_reward` will be
      # penalized by an extra penalty
      # with default -1, if not provided in `anomaly_percent_dict`
      anomaly_percent_reward = Reward(
          reward_func=reward_func,
          min_unpenalized=-max_acceptable_diff,
          max_unpenalized=float("inf"),
          penalize_method=PenalizeMethod.ADDITIVE.value,
          penalty=penalty,
      )
  
      return anomaly_percent_reward
  
imports: import numpy
  import pandas
  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 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 START_TIME_COL
  from greykite.common.constants import TIME_COL
  from greykite.common.viz.timeseries_annotate import plot_anomalies_over_forecast_vs_actual
  from greykite.detection.common.ad_evaluation import f1_score
  from greykite.detection.common.ad_evaluation import precision_score
  from greykite.detection.common.ad_evaluation import recall_score
  from greykite.detection.detector.ad_utils import get_anomaly_df
  from greykite.detection.detector.ad_utils import partial_return
  from greykite.detection.detector.constants import PHASE_PREDICT
  from greykite.detection.detector.constants import PHASE_TRAIN
  from greykite.detection.detector.constants import PenalizeMethod
  from greykite.detection.detector.optimizer import Optimizer
  from greykite.detection.detector.reward import Reward
label_desc: Use image node_id 1 for calling a global function with example usage: build_anomaly_percent_reward(anomaly_percent_dict) and returns: anomaly_percent_reward, unknown