code: def build_agg_lag_df(
      value_col,
      df=None,
      orders_list=[],
      interval_list=[],
      agg_func="mean",
      agg_name=cst.AGG_LAG_INFIX,
      max_order=None,
  ):
      """A function which returns a dataframe including aggregated
      (e.g. averaged) time series lags in the form of dataframe columns.
      By "aggregated lags", we mean an aggregate of several lags using an
      aggregation function given in "agg_func".
      The advantage of "aggregated lags" over regular lags is we can aggregate
      (e.g. average) many lags in the past instead of using a large number of lags.
      This is useful in many applications and avoids over-fitting.
  
      For a time series mathematically denoted by Y(t),
      one could consider the average lag processes as follows:
          the average of last 3 values:
              "avg(t) = (Y(t-1) + Y(t-2) + Y(t-3)) / 3"
          the average of 7th, 14th and 21st lags:
              "avg(t) = (Y(t-7) + Y(t-14) + Y(t-21)) / 3"
  
      See following references:
          Reza Hosseini et al. (2014)
          Non-linear time-varying stochastic models for agroclimate risk assessment,
          Environmental and Ecological Statistics
          https://link.springer.com/article/10.1007/s10651-014-0295-2
  
          Alireza Hosseini et al. (2017)
          Capturing the time-dependence in the precipitation process for weather risk assessment,
          Stochastic Environmental Research and Risk Assessment
          https://link.springer.com/article/10.1007/s00477-016-1285-8
  
      :param value_col: str
          the column name for the values of interest
      :param df: Optional[pd.DataFrame]
          the data frame which includes the time series of interest
      :param orders_list: List[int]
          a list including the order range for the average lags. For example if
          agg_func = np.mean and orders_list = [[1, 2, 3], [7, 14, 21]]
          then we construct two averaged lags:
              avg(t) = (Y(t-1) + Y(t-2) + Y(t-3)) / 3 and
              avg(t) = (Y(t-7) + Y(t-14) + Y(t-21)) / 3
      :param interval_list: List[tuple[int]]
          a list of (lag) intervals
          where interval is a tuple of length 2 with
              - first element denoting the lower bound and
              - second is the upper
          For example if interval_list = [(1, 3), (8, 11)]
          then we construct two "average lagged" variables:
              avg(t) = (Y(t-1) + Y(t-2) + Y(t-3)) / 3 and
              avg(t) = (Y(t-8) + Y(t-9) + Y(t-10) + Y(t-11)) / 4
      :param agg_func: "mean" or callable, default: "mean"
          the function used to aggregate the lag orders for each of
          orders specified in either of order_list or interval_list.
          Typically this function is an averaging function such as
          np.mean or np.median but more sophisticated functions are allowed.
          If "mean", uses `pandas.DataFrame.mean`.
      :param agg_name: str, default: "avglag"
          the aggregate function name used in constructing the column names for
          the output data frame.
          For example if
              - value_col = "y"
              - orders = [7 , 14, 21]
              - agg_name = "avglag"
          then the column name appearing in the output data frame
          will be "y_avglag_7_14_21".
      :param max_order: Optional[int]
          maximum order of lags needed in calculations of lag aggregates
          this is usually calculated/inferred from these arguments:
              orders_list, interval_list
          unless the max_order is already pre-calculated before calling
          this function. Hence this argument is optional and only included for
          computational efficiency gains.
      :return: dict
          dictionary with following items:
              - "col_names": List[str]
                  the generated column names
              - "agg_lag_df": Optional[pd.DataFrame]
                  a data frame with the average lag columns.
                  The column names are constructed in a way
                  that reflects what lags are averaged. For example if
                      - value_col = "y"
                      - agg_name = "avglag"
                      - orders_list = [[1, 2, 3], [7, 14, 21]]
                  Then the column names are
                  "y_avglag_1_2_3", "y_avglag_7_14_21"
                  and if
                      - interval_list = [(1, 3), (8, 11)]
                  Then the column names are
                  "y_avglag_1_to_3", "y_avglag_8_to_11"
      """
  
      if orders_list is None and interval_list is None:
          raise ValueError(
              "at least one of 'orders_list' or 'interval_list' must be provided"
          )
      # Finds out which lags we need by finding the maximum lag used.
      # Note that `max_order` should be usually passed as None (default)
      # unless it is pre-calculated before calling this function.
      if max_order is None:
          max_order = min_max_lag_order(
              lag_dict=None,
              agg_lag_dict={
                  "orders_list": orders_list,
                  "interval_list": interval_list,
              },
          )["max_order"]
  
      # intializes the returned items
      agg_lag_df = None
      col_names = []
  
      if df is not None:
          lag_info = build_lag_df(
              df=df.copy(),
              value_col=value_col,
              max_order=max_order,
              orders=None,
          )
          lag_df = lag_info["lag_df"]
          agg_lag_df_list = []
  
      for orders in orders_list:
          if len(orders) > len(set(orders)):
              raise Exception(
                  "a list of orders in orders_list contains a duplicate element"
              )
          col_suffix = "_".join([str(x) for x in orders])
          orders_col_index = [x - 1 for x in orders]
          col_name = f"{value_col}_{agg_name}_{col_suffix}"
          col_names.append(col_name)
          if df is not None:
              if agg_func == "mean":
                  # uses vectorized mean for speed
                  agg_lag_df_list.append(
                      lag_df.iloc[:, orders_col_index]
                      .mean(axis=1)
                      .rename(col_name)
                  )
              else:
                  # generic aggregation
                  agg_lag_df_list.append(
                      lag_df.iloc[:, orders_col_index]
                      .apply(agg_func, axis=1)
                      .rename(col_name)
                  )
  
      for interval in interval_list:
          if len(interval) != 2:
              raise Exception("interval must be a tuple of length 2")
          lower = interval[0]
          upper = interval[1]
          if lower > upper:
              raise Exception(
                  "we must have interval[0] <= interval[1], "
                  "for each interval in interval_list"
              )
          orders = range(lower, upper + 1)
          col_suffix = f"{lower}_to_{upper}"
          orders_col_index = [x - 1 for x in orders]
          col_name = f"{value_col}_{agg_name}_{col_suffix}"
          col_names.append(col_name)
          if df is not None:
              agg_lag_df_list.append(
                  lag_df.iloc[:, orders_col_index]
                  .apply(agg_func, axis=1)
                  .rename(col_name)
              )
  
      if df is not None:
          agg_lag_df = pd.concat(
              objs=agg_lag_df_list, axis=1, ignore_index=False
          )
  
      return {"agg_lag_df": agg_lag_df, "col_names": col_names}
  
imports: import numpy
  import pandas
  from greykite.common import constants
label_desc: Use image node_id 3 for calling a global function with example usage: build_agg_lag_df(value_col, df, orders_list, interval_list, agg_func, agg_name, max_order) and returns: dict