class_docstr: Prepare hierarchical data, including aggregate levels, from bottom level.
  
  This transformer adds aggregate levels via summation to a DataFrame with a
  multiindex. The aggregate levels are included with the special tag "__total"
  in the index. The aggregate nodes are discovered from top-to-bottom from
  the input data multiindex.
  
  Parameters
  ----------
  flatten_single_level : boolean (default=True)
      Remove aggregate nodes, i.e. ("__total"), where there is only a single
      child to the level
  
  See Also
  --------
  ReconcilerForecaster
  Reconciler
  
  References
  ----------
  .. [1] https://otexts.com/fpp3/hierarchical.html
  
  Examples
  --------
  >>> from sktime.transformations.hierarchical.aggregate import Aggregator
  >>> from sktime.utils._testing.hierarchical import _bottom_hier_datagen
  >>> agg = Aggregator()
  >>> y = _bottom_hier_datagen(
  ...     no_bottom_nodes=3,
  ...     no_levels=1,
  ...     random_seed=123,
  ... )
  >>> y = agg.fit_transform(y)
docstr: Transform X and return a transformed version.
  
  private _transform containing core logic, called from transform
  
  Parameters
  ----------
  X : Panel of pd.DataFrame data to be transformed.
  y : Ignored argument for interface compatibility.
  
  Returns
  -------
  Transformed version of X
code: def _transform(self, X, y=None):
      """Transform X and return a transformed version.
  
      private _transform containing core logic, called from transform
  
      Parameters
      ----------
      X : Panel of pd.DataFrame data to be transformed.
      y : Ignored argument for interface compatibility.
  
      Returns
      -------
      Transformed version of X
      """
      if X.index.nlevels == 1:
          warn(
              "Aggregator is intended for use with X.index.nlevels > 1. "
              "Returning X unchanged.",
              obj=self,
          )
          return X
      # check the tests are ok
      if not _check_index_no_total(X):
          warn(
              "Found elements in the index of X named '__total'. Removing "
              "these levels and aggregating.",
              obj=self,
          )
          X = self._inverse_transform(X)
  
      # starting from top aggregate
      df_out = X.copy()
      for i in range(0, X.index.nlevels - 1, 1):
          # finding "__totals" parent/child from (up -> down)
          indx_grouper = np.arange(0, i, 1).tolist()
          indx_grouper.append(X.index.nlevels - 1)
  
          out = X.groupby(level=indx_grouper).sum()
  
          # get new index with aggregate levels to match with old
          new_idx = []
          for j in range(0, X.index.nlevels - 1, 1):
              if j in indx_grouper:
                  new_idx.append(out.index.get_level_values(j))
              else:
                  new_idx.append(["__total"] * len(out.index))
  
          # add in time index
          new_idx.append(out.index.get_level_values(-1))
  
          new_idx = pd.MultiIndex.from_arrays(
              new_idx, names=X.index.names
          )
  
          out = out.set_index(new_idx)
  
          df_out = pd.concat([out, df_out])
  
      # now remove duplicated aggregate indexes
      if self.flatten_single_levels:
          new_index = _flatten_single_indexes(X)
  
          nm = X.index.names[-1]
          if nm is None:
              nm = "level_" + str(X.index.nlevels - 1)
          else:
              pass
  
          # now reindex with new non-duplicated axis
          df_out = (
              df_out.reset_index(level=-1)
              .loc[new_index]
              .set_index(nm, append=True)
          ).rename_axis(X.index.names, axis=0)
  
      df_out = df_out.sort_index()
  
      return df_out
  
file_path: sktime/sktime/transformations/hierarchical/aggregate.py
imports: import numpy
  import pandas
  from sktime.transformations.base import BaseTransformer
  from sktime.utils.warnings import warn
label_desc: Use image node_id 2 for calling the Aggregator obj's underlying member method code with example usage: obj._transform(X, y) and returns: df_out, X