code: def _get_g_matrix_bu(X):
      """Determine the reconciliation "G" matrix for the bottom up method.
  
      Reconciliation methods require the G matrix. The G matrix is used to redefine
      base forecasts for the entire hierarchy to the bottom-level only before
      summation using the S matrix.
  
      Please refer to [1]_ for further information.
  
      Parameters
      ----------
      X :  Panel of mtype pd_multiindex_hier
  
      Returns
      -------
      g_matrix : pd.DataFrame with rows equal to the number of bottom level nodes
          only, i.e. with no aggregate nodes, and columns equal to the number of
          unique nodes in the hierarchy. The matrix indexes is inherited from the
          input data, with the time level removed.
  
      References
      ----------
      .. [1] https://otexts.com/fpp3/hierarchical.html
      """
      # get bottom level indexes
      bl_inds = (
          X.loc[~(X.index.get_level_values(level=-2).isin(["__total"]))]
          .index.droplevel(level=-1)
          .unique()
      )
  
      # get all level indexes
      al_inds = X.droplevel(level=-1).index.unique()
  
      g_matrix = pd.DataFrame(
          [
              [0.0 for i in range(len(bl_inds))]
              for i in range(len(al_inds))
          ],
          index=al_inds,
      )
      g_matrix.columns = bl_inds
  
      # now insert indicator for bottom level
      for i in g_matrix.columns:
          g_matrix.loc[g_matrix.index == i, i] = 1.0
  
      return g_matrix.transpose()
  
imports: import numpy
  import pandas
  from numpy.linalg import inv
  from sktime.transformations.base import BaseTransformer
  from sktime.transformations.hierarchical.aggregate import _check_index_no_total
  from sktime.utils.warnings import warn
label_desc: Use image node_id 2 for calling a global function with example usage: _get_g_matrix_bu(X) and returns: g_matrix