code: def iou(
      y_true: Union[
          pd.Series,
          pd.DataFrame,
          List[Union[Tuple[pd.Timestamp, pd.Timestamp], pd.Timestamp]],
          Dict[
              str,
              List[
                  Union[Tuple[pd.Timestamp, pd.Timestamp], pd.Timestamp]
              ],
          ],
      ],
      y_pred: Union[
          pd.Series,
          pd.DataFrame,
          List[Union[Tuple[pd.Timestamp, pd.Timestamp], pd.Timestamp]],
          Dict[
              str,
              List[
                  Union[Tuple[pd.Timestamp, pd.Timestamp], pd.Timestamp]
              ],
          ],
      ],
  ) -> Union[float, Dict[str, float]]:
      """IoU (Intersection over Union) score of prediction.
  
      Intersection over union is the length ratio between time segments that are
      identified as anomalous in both lists and those identified by at least one
      of the two lists.
  
      When the input is anomaly labels, metric calculation counts the number of
      anomalous time points.
  
      When the input is lists of anomalous time windows, metric calculation
      measure the length of time segments.
  
      Parameters
      ----------
      y_true: pandas Series or DataFrame, list, or dict
          Labels or lists of true anomalies.
  
          - If pandas Series, it is treated as binary labels along time index.
          - If pandas DataFrame, each column is a binary series and is treated as
            an independent type of anomaly.
          - If list, a list of events where an event is a pandas Timestamp if it
            is instantaneous or a 2-tuple of pandas Timestamps if it is a closed
            time interval.
          - If dict, each key-value pair is a list of events and is treated as an
            independent type of anomaly.
  
      y_pred: pandas Series or DataFrame, list, or dict
          Labels or lists of predicted anomalies.
  
          - If pandas Series, it is treated as binary labels along time index.
          - If pandas DataFrame, each column is a binary series and is treated as
            an independent type of anomaly.
          - If list, a list of events where an event is a pandas Timestamp if it
            is instantaneous or a 2-tuple of pandas Timestamps if it is a closed
            time interval.
          - If dict, each key-value pair is a list of events and is treated as an
            independent type of anomaly.
  
      Returns
      -------
      float or dict
          Score(s) for each type of anomaly.
  
      """
      if type(y_true) != type(y_pred):
          raise TypeError("y_true and y_pred must have same type.")
  
      if isinstance(y_true, pd.Series) and isinstance(
          y_pred, pd.Series
      ):
          try:
              pd.testing.assert_index_equal(y_true.index, y_pred.index)
          except AssertionError:
              raise ValueError(
                  "y_true and y_pred must have identical index"
              )
          if (
              y_true.clip(0, 1).round() + y_pred.clip(0, 1).round()
          ).clip(0, 1).sum() != 0:
              return (
                  y_true.clip(0, 1).round() * y_pred.clip(0, 1).round()
              ).sum() / (
                  y_true.clip(0, 1).round() + y_pred.clip(0, 1).round()
              ).clip(
                  0, 1
              ).sum()
          else:
              return float("nan")
      elif isinstance(y_true, pd.DataFrame) and isinstance(
          y_pred, pd.DataFrame
      ):
          if set(y_true.columns) != set(y_pred.columns):
              raise ValueError(
                  "y_true and y_pred must have identical columns."
              )
          return {
              col: iou(y_true[col], y_pred[col])
              for col in y_true.columns
          }
      elif isinstance(y_true, list) and isinstance(y_pred, list):
          y_int = AndAggregator().aggregate(
              {"y_true": y_true, "y_pred": y_pred}
          )
          y_union = OrAggregator().aggregate(
              {"y_true": y_true, "y_pred": y_pred}
          )
          len_int = sum(
              [
                  (w[1] - w[0]).total_seconds()
                  if isinstance(w, tuple)
                  else 0
                  for w in y_int
              ]
          )
          len_union = sum(
              [
                  (w[1] - w[0]).total_seconds()
                  if isinstance(w, tuple)
                  else 0
                  for w in y_union
              ]
          )
          if len_union == 0:
              return float("nan")
          return len_int / len_union
      elif isinstance(y_true, dict) and isinstance(y_pred, dict):
          return {
              key: iou(y_true[key], y_pred[key])
              for key in y_true.keys()
          }
      else:
          raise TypeError(
              "y_true and y_pred must be pandas Series or DataFrame, list, or a "
              "dict of lists"
          )
  
imports: from typing import Dict, List, Tuple, Union, overload
  import pandas
  from ..aggregator import AndAggregator, OrAggregator
  from ..data import validate_events
label_desc: Use image node_id 20 for calling a global function with example usage: iou(y_true, y_pred) and returns: unknown, float, unknown, unknown, float, unknown