code: def epsilon(
      data, dv=None, within=None, subject=None, correction="gg"
  ):
      """Epsilon adjustement factor for repeated measures.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame containing the repeated measurements.
          Both wide and long-format dataframe are supported for this function.
          To test for an interaction term between two repeated measures factors
          with a wide-format dataframe, ``data`` must have a two-levels
          :py:class:`pandas.MultiIndex` columns.
      dv : string
          Name of column containing the dependent variable (only required if
          ``data`` is in long format).
      within : string
          Name of column containing the within factor (only required if ``data``
          is in long format).
          If ``within`` is a list with two strings, this function computes
          the epsilon factor for the interaction between the two within-subject
          factor.
      subject : string
          Name of column containing the subject identifier (only required if
          ``data`` is in long format).
      correction : string
          Specify the epsilon version:
  
          * ``'gg'``: Greenhouse-Geisser
          * ``'hf'``: Huynh-Feldt
          * ``'lb'``: Lower bound
  
      Returns
      -------
      eps : float
          Epsilon adjustement factor.
  
      See Also
      --------
      sphericity : Mauchly and JNS test for sphericity.
      homoscedasticity : Test equality of variance.
  
      Notes
      -----
      The lower bound epsilon is:
  
      .. math:: lb = \\frac{1}{\\text{dof}},
  
      where the degrees of freedom :math:`\\text{dof}` is the number of groups
      :math:`k` minus 1 for one-way design and :math:`(k_1 - 1)(k_2 - 1)`
      for two-way design
  
      The Greenhouse-Geisser epsilon is given by:
  
      .. math::
  
          \\epsilon_{GG} = \\frac{k^2(\\overline{\\text{diag}(S)} -
          \\overline{S})^2}{(k-1)(\\sum_{i=1}^{k}\\sum_{j=1}^{k}s_{ij}^2 -
          2k\\sum_{j=1}^{k}\\overline{s_i}^2 + k^2\\overline{S}^2)}
  
      where :math:`S` is the covariance matrix, :math:`\\overline{S}` the
      grandmean of S and :math:`\\overline{\\text{diag}(S)}` the mean of all the
      elements on the diagonal of S (i.e. mean of the variances).
  
      The Huynh-Feldt epsilon is given by:
  
      .. math::
  
          \\epsilon_{HF} = \\frac{n(k-1)\\epsilon_{GG}-2}{(k-1)
          (n-1-(k-1)\\epsilon_{GG})}
  
      where :math:`n` is the number of observations.
  
      Missing values are automatically removed from data (listwise deletion).
  
      Examples
      --------
      Using a wide-format dataframe
  
      >>> import pandas as pd
      >>> import pingouin as pg
      >>> data = pd.DataFrame({'A': [2.2, 3.1, 4.3, 4.1, 7.2],
      ...                      'B': [1.1, 2.5, 4.1, 5.2, 6.4],
      ...                      'C': [8.2, 4.5, 3.4, 6.2, 7.2]})
      >>> gg = pg.epsilon(data, correction='gg')
      >>> hf = pg.epsilon(data, correction='hf')
      >>> lb = pg.epsilon(data, correction='lb')
      >>> print("%.2f %.2f %.2f" % (lb, gg, hf))
      0.50 0.56 0.62
  
      Now using a long-format dataframe
  
      >>> data = pg.read_dataset('rm_anova2')
      >>> data.head()
         Subject Time   Metric  Performance
      0        1  Pre  Product           13
      1        2  Pre  Product           12
      2        3  Pre  Product           17
      3        4  Pre  Product           12
      4        5  Pre  Product           19
  
      Let's first calculate the epsilon of the *Time* within-subject factor
  
      >>> pg.epsilon(data, dv='Performance', subject='Subject',
      ...            within='Time')
      1.0
  
      Since *Time* has only two levels (Pre and Post), the sphericity assumption
      is necessarily met, and therefore the epsilon adjustement factor is 1.
  
      The *Metric* factor, however, has three levels:
  
      >>> round(pg.epsilon(data, dv='Performance', subject='Subject',
      ...                  within=['Metric']), 3)
      0.969
  
      The epsilon value is very close to 1, meaning that there is no major
      violation of sphericity.
  
      Now, let's calculate the epsilon for the interaction between the two
      repeated measures factor:
  
      >>> round(pg.epsilon(data, dv='Performance', subject='Subject',
      ...                  within=['Time', 'Metric']), 3)
      0.727
  
      Alternatively, we could use a wide-format dataframe with two column
      levels:
  
      >>> # Pivot from long-format to wide-format
      >>> piv = data.pivot(index='Subject', columns=['Time', 'Metric'], values='Performance')
      >>> piv.head()
      Time        Pre                  Post
      Metric  Product Client Action Product Client Action
      Subject
      1            13     12     17      18     30     34
      2            12     19     18       6     18     30
      3            17     19     24      21     31     32
      4            12     25     25      18     39     40
      5            19     27     19      18     28     27
  
      >>> round(pg.epsilon(piv), 3)
      0.727
  
      which gives the same epsilon value as the long-format dataframe.
      """
      assert isinstance(
          data, pd.DataFrame
      ), "Data must be a pandas Dataframe."
  
      # If data is in long-format, convert to wide-format
      if all([v is not None for v in [dv, within, subject]]):
          data = _long_to_wide_rm(
              data, dv=dv, within=within, subject=subject
          )
  
      # From now on we assume that data is in wide-format and contains only
      # the relevant columns.
      # Drop rows with missing values
      data = data.dropna()
  
      # Support for two-way factor of shape (2, N)
      data = _check_multilevel_rm(data, func="epsilon")
  
      # Covariance matrix
      S = data.cov(numeric_only=True)
      n, k = data.shape
  
      # Epsilon is always 1 with only two repeated measures.
      if k <= 2:
          return 1.0
  
      # Degrees of freedom
      if S.columns.nlevels == 1:
          # One-way design
          dof = k - 1
      else:
          # Two-way design (>2, >2)
          ka, kb = S.columns.levshape
          dof = (ka - 1) * (kb - 1)
  
      # Lower bound
      if correction == "lb":
          return 1 / dof
  
      # Greenhouse-Geisser
      # Method 1. Sums of squares. (see real-statistics.com)
      mean_var = np.diag(S).mean()
      S_mean = S.mean().mean()
      ss_mat = (S**2).sum().sum()
      ss_rows = (S.mean(1) ** 2).sum().sum()
      num = (k * (mean_var - S_mean)) ** 2
      den = (k - 1) * (ss_mat - 2 * k * ss_rows + k**2 * S_mean**2)
      eps = np.min([num / den, 1])
  
      # Method 2. Eigenvalues.
      # Sv = S.to_numpy()
      # S_pop = Sv - Sv.mean(0)[:, None] - Sv.mean(1)[None, :] + Sv.mean()
      # eig = np.linalg.eigvalsh(S_pop)
      # eig = eig[eig > 0.1]
      # V = eig.sum()**2 / np.sum(eig**2)
      # eps = np.min([V / dof, 1])
  
      # Huynh-Feldt
      if correction == "hf":
          num = n * dof * eps - 2
          den = dof * (n - 1 - dof * eps)
          eps = np.min([num / den, 1])
      return eps
  
file_path: pingouin/pingouin/distribution.py
imports: import warnings
  import scipy.stats
  import numpy
  import pandas
  from collections import namedtuple
  from pingouin.utils import _flatten_list
  from pingouin.utils import remove_na, _postprocess_dataframe
label_desc: Use image node_id 7 for calling a global function with example usage: epsilon(data, dv, within, subject, correction) and returns: eps, int, unknown