code: def rm_anova(
      data=None,
      dv=None,
      within=None,
      subject=None,
      correction="auto",
      detailed=False,
      effsize="ng2",
  ):
      """One-way and two-way repeated measures ANOVA.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame. Note that this function can also directly be used as a
          :py:class:`pandas.DataFrame` method, in which case this argument is no
          longer needed.
          Both wide and long-format dataframe are supported for one-way repeated
          measures ANOVA. However, ``data`` must be in long format for two-way
          repeated measures.
      dv : string
          Name of column containing the dependent variable (only required if
          ``data`` is in long format).
      within : string or list of string
          Name of column containing the within factor (only required if ``data``
          is in long format).
          If ``within`` is a single string, then compute a one-way repeated
          measures ANOVA, if ``within`` is a list with two strings,
          compute a two-way repeated measures ANOVA.
      subject : string
          Name of column containing the subject identifier (only required if
          ``data`` is in long format).
      correction : string or boolean
          If True, also return the Greenhouse-Geisser corrected p-value.
  
          The default for one-way design is to compute Mauchly's test of
          sphericity to determine whether the p-values needs to be corrected
          (see :py:func:`pingouin.sphericity`).
  
          The default for two-way design is to return both the uncorrected and
          Greenhouse-Geisser corrected p-values. Note that sphericity test for
          two-way design are not currently implemented in Pingouin.
      detailed : boolean
          If True, return a full ANOVA table.
      effsize : string
          Effect size. Must be one of 'np2' (partial eta-squared), 'n2'
          (eta-squared) or 'ng2'(generalized eta-squared, default). Note that for
          one-way repeated measure ANOVA, eta-squared is the same as the generalized eta-squared.
  
      Returns
      -------
      aov : :py:class:`pandas.DataFrame`
          ANOVA summary:
  
          * ``'Source'``: Name of the within-group factor
          * ``'ddof1'``: Degrees of freedom (numerator)
          * ``'ddof2'``: Degrees of freedom (denominator)
          * ``'F'``: F-value
          * ``'p-unc'``: Uncorrected p-value
          * ``'ng2'``: Generalized eta-square effect size
          * ``'eps'``: Greenhouse-Geisser epsilon factor (= index of sphericity)
          * ``'p-GG-corr'``: Greenhouse-Geisser corrected p-value
          * ``'W-spher'``: Sphericity test statistic
          * ``'p-spher'``: p-value of the sphericity test
          * ``'sphericity'``: sphericity of the data (boolean)
  
      See Also
      --------
      anova : One-way and N-way ANOVA
      mixed_anova : Two way mixed ANOVA
      friedman : Non-parametric one-way repeated measures ANOVA
  
      Notes
      -----
      Data can be in wide or long format for one-way repeated measures ANOVA but
      *must* be in long format for two-way repeated measures ANOVA.
  
      In one-way repeated-measures ANOVA, the total variance (sums of squares)
      is divided into three components
  
      .. math::
          SS_{\\text{total}} = SS_{\\text{effect}} +
          (SS_{\\text{subjects}} + SS_{\\text{error}})
  
      with
  
      .. math::
          SS_{\\text{total}} = \\sum_i^r \\sum_j^n (Y_{ij} - \\overline{Y})^2
  
          SS_{\\text{effect}} = \\sum_i^r n_i(\\overline{Y_i} - \\overline{Y})^2
  
          SS_{\\text{subjects}} = r\\sum (\\overline{Y}_s - \\overline{Y})^2
  
          SS_{\\text{error}} = SS_{\\text{total}} - SS_{\\text{effect}} -
          SS_{\\text{subjects}}
  
  
      where :math:`i=1,...,r; j=1,...,n_i`, :math:`r` is the number of
      conditions, :math:`n_i` the number of observations for each condition,
      :math:`\\overline{Y}` the grand mean of the data, :math:`\\overline{Y_i}`
      the mean of the :math:`i^{th}` condition and :math:`\\overline{Y}_{subj}`
      the mean of the :math:`s^{th}` subject.
  
      The F-statistics is then defined as:
  
      .. math::
  
          F^* = \\frac{MS_{\\text{effect}}}{MS_{\\text{error}}} =
          \\frac{\\frac{SS_{\\text{effect}}}
          {r-1}}{\\frac{SS_{\\text{error}}}{(n - 1)(r - 1)}}
  
      and the p-value can be calculated using a F-distribution with
      :math:`v_{\\text{effect}} = r - 1` and
      :math:`v_{\\text{error}} = (n - 1)(r - 1)` degrees of freedom.
  
      The default effect size reported in Pingouin is the generalized eta-squared,
      which is equivalent to eta-squared for one-way repeated measures ANOVA.
  
      .. math::
          \\eta_g^2 = \\frac{SS_{\\text{effect}}}{SS_{\\text{total}}}
  
      The partial eta-squared is defined as:
  
      .. math::
          \\eta_p^2 = \\frac{SS_{\\text{effect}}}{SS_{\\text{effect}} + SS_{\\text{error}}}
  
      Missing values are automatically removed using a strict listwise approach (= complete-case
      analysis). In other words, any subject with one or more missing value(s) is completely removed
      from the dataframe prior to running the test. This could drastically decrease the power of the
      ANOVA if many missing values are present. In that case, we strongly recommend using linear
      mixed effect modelling, which can handle missing values in repeated measures.
  
      .. warning:: The epsilon adjustement factor of the interaction in
          two-way repeated measures ANOVA where both factors have more than
          two levels slightly differs than from R and JASP.
          Please always make sure to double-check your results with another
          software.
  
      .. warning:: Sphericity tests for the interaction term of a two-way
          repeated measures ANOVA are not currently supported in Pingouin.
          Instead, please refer to the Greenhouse-Geisser epsilon value
          (a value close to 1 indicates that sphericity is met.) For more
          details, see :py:func:`pingouin.sphericity`.
  
      Examples
      --------
      1. One-way repeated measures ANOVA using a wide-format dataset
  
      >>> import pingouin as pg
      >>> data = pg.read_dataset('rm_anova_wide')
      >>> pg.rm_anova(data)
         Source  ddof1  ddof2         F     p-unc       ng2       eps
      0  Within      3     24  5.200652  0.006557  0.346392  0.694329
  
      2. One-way repeated-measures ANOVA using a long-format dataset.
  
      We're also specifying two additional options here: ``detailed=True`` means
      that we'll get a more detailed ANOVA table, and ``effsize='np2'``
      means that we want to get the partial eta-squared effect size instead
      of the default (generalized) eta-squared.
  
      >>> df = pg.read_dataset('rm_anova')
      >>> aov = pg.rm_anova(dv='DesireToKill', within='Disgustingness',
      ...                   subject='Subject', data=df, detailed=True, effsize="np2")
      >>> aov.round(3)
                 Source       SS  DF      MS       F  p-unc    np2  eps
      0  Disgustingness   27.485   1  27.485  12.044  0.001  0.116  1.0
      1           Error  209.952  92   2.282     NaN    NaN    NaN  NaN
  
      3. Two-way repeated-measures ANOVA
  
      >>> aov = pg.rm_anova(dv='DesireToKill', within=['Disgustingness', 'Frighteningness'],
      ...                   subject='Subject', data=df)
  
      4. As a :py:class:`pandas.DataFrame` method
  
      >>> df.rm_anova(dv='DesireToKill', within='Disgustingness', subject='Subject',  detailed=False)
                 Source  ddof1  ddof2          F     p-unc       ng2  eps
      0  Disgustingness      1     92  12.043878  0.000793  0.025784  1.0
      """
      assert effsize in [
          "n2",
          "np2",
          "ng2",
      ], "effsize must be n2, np2 or ng2."
      if isinstance(within, list):
          assert len(within) > 0, "Within cannot be empty."
          if len(within) == 1:
              within = within[0]
          elif len(within) == 2:
              return rm_anova2(
                  dv=dv,
                  within=within,
                  data=data,
                  subject=subject,
                  effsize=effsize,
              )
          else:
              raise ValueError(
                  "Repeated measures ANOVA with three or more factors is not supported."
              )
  
      # Convert from wide to long-format, if needed
      if all([v is None for v in [dv, within, subject]]):
          assert isinstance(data, pd.DataFrame)
          data = (
              data._get_numeric_data().dropna()
          )  # Listwise deletion of missing values
          assert (
              data.shape[0] > 2
          ), "Data must have at least 3 non-missing rows."
          assert (
              data.shape[1] > 1
          ), "Data must contain at least two columns."
          data["Subj"] = np.arange(data.shape[0])
          data = data.melt(
              id_vars="Subj", var_name="Within", value_name="DV"
          )
          subject, within, dv = "Subj", "Within", "DV"
  
      # Check dataframe
      data = _check_dataframe(
          dv=dv,
          within=within,
          data=data,
          subject=subject,
          effects="within",
      )
  
      assert (
          not data[within].isnull().any()
      ), "Cannot have missing values in `within`."
      assert (
          not data[subject].isnull().any()
      ), "Cannot have missing values in `subject`."
  
      # Pivot and melt the table. This has several effects:
      # 1) Force missing values to be explicit (a NaN cell is created)
      # 2) Automatic collapsing to the mean if multiple within factors are present
      # 3) If using dropna, remove rows with missing values (listwise deletion).
      # The latter is the same behavior as JASP (= strict complete-case analysis).
      data_piv = data.pivot_table(
          index=subject, columns=within, values=dv, observed=True
      )
      data_piv = data_piv.dropna()
      data = data_piv.melt(
          ignore_index=False, value_name=dv
      ).reset_index()
  
      # Groupby
      # I think that observed=True is actually not needed here since we have already used
      # `observed=True` in pivot_table.
      grp_with = data.groupby(within, observed=True, group_keys=False)[
          dv
      ]
      rm = list(data[within].unique())
      n_rm = len(rm)
      n_obs = int(grp_with.count().max())
      grandmean = data[dv].mean(numeric_only=True)
  
      # Calculate sums of squares
      ss_with = (
          (grp_with.mean(numeric_only=True) - grandmean) ** 2
          * grp_with.count()
      ).sum()
      ss_resall = grp_with.apply(lambda x: (x - x.mean()) ** 2).sum()
      # sstotal = sstime + ss_resall =  sstime + (sssubj + sserror)
      # ss_total = ((data[dv] - grandmean)**2).sum()
      # We can further divide the residuals into a within and between component:
      grp_subj = data.groupby(subject, observed=True)[dv]
      ss_resbetw = n_rm * np.sum(
          (grp_subj.mean(numeric_only=True) - grandmean) ** 2
      )
      ss_reswith = ss_resall - ss_resbetw
  
      # Calculate degrees of freedom
      ddof1 = n_rm - 1
      ddof2 = ddof1 * (n_obs - 1)
  
      # Calculate MS, F and p-values
      ms_with = ss_with / ddof1
      ms_reswith = ss_reswith / ddof2
      fval = ms_with / ms_reswith
      p_unc = f(ddof1, ddof2).sf(fval)
  
      # Calculating effect sizes (see Bakeman 2005; Lakens 2013)
      # https://github.com/raphaelvallat/pingouin/issues/251
      if effsize == "np2":
          # Partial eta-squared
          ef = ss_with / (ss_with + ss_reswith)
      else:
          # (Generalized) eta-squared, ng2 == n2
          ef = ss_with / (ss_with + ss_resall)
  
      # Compute sphericity using Mauchly test, on the wide-format dataframe
      # Sphericity assumption only applies if there are more than 2 levels
      if correction == "auto" or (correction is True and n_rm >= 3):
          spher, W_spher, _, _, p_spher = sphericity(
              data_piv, alpha=0.05
          )
          if correction == "auto":
              correction = True if not spher else False
      else:
          correction = False
  
      # Compute epsilon adjustement factor
      eps = epsilon(data_piv, correction="gg")
  
      # If required, apply Greenhouse-Geisser correction for sphericity
      if correction:
          corr_ddof1, corr_ddof2 = (
              np.maximum(d * eps, 1.0) for d in (ddof1, ddof2)
          )
          p_corr = f(corr_ddof1, corr_ddof2).sf(fval)
  
      # Create output dataframe
      if not detailed:
          aov = pd.DataFrame(
              {
                  "Source": within,
                  "ddof1": ddof1,
                  "ddof2": ddof2,
                  "F": fval,
                  "p-unc": p_unc,
                  effsize: ef,
                  "eps": eps,
              },
              index=[0],
          )
          if correction:
              aov["p-GG-corr"] = p_corr
              aov["W-spher"] = W_spher
              aov["p-spher"] = p_spher
              aov["sphericity"] = spher
  
          col_order = [
              "Source",
              "ddof1",
              "ddof2",
              "F",
              "p-unc",
              "p-GG-corr",
              effsize,
              "eps",
              "sphericity",
              "W-spher",
              "p-spher",
          ]
      else:
          aov = pd.DataFrame(
              {
                  "Source": [within, "Error"],
                  "SS": [ss_with, ss_reswith],
                  "DF": [ddof1, ddof2],
                  "MS": [ms_with, ms_reswith],
                  "F": [fval, np.nan],
                  "p-unc": [p_unc, np.nan],
                  effsize: [ef, np.nan],
                  "eps": [eps, np.nan],
              }
          )
          if correction:
              aov["p-GG-corr"] = [p_corr, np.nan]
              aov["W-spher"] = [W_spher, np.nan]
              aov["p-spher"] = [p_spher, np.nan]
              aov["sphericity"] = [spher, np.nan]
  
          col_order = [
              "Source",
              "SS",
              "DF",
              "MS",
              "F",
              "p-unc",
              "p-GG-corr",
              effsize,
              "eps",
              "sphericity",
              "W-spher",
              "p-spher",
          ]
  
      aov = aov.reindex(columns=col_order)
      aov.dropna(how="all", axis=1, inplace=True)
      return _postprocess_dataframe(aov)
  
file_path: pingouin/pingouin/parametric.py
imports: import warnings
  from collections.abc import Iterable
  import numpy
  import pandas
  from scipy.stats import f
  import pandas_flavor
  from pingouin import _check_dataframe, remove_na, _flatten_list, bayesfactor_ttest, epsilon, sphericity, _postprocess_dataframe
label_desc: Use image node_id 2 for calling a global function with example usage: rm_anova(data, dv, within, subject, correction, detailed, effsize) and returns: _postprocess_dataframe, rm_anova2