code: def mixed_anova(
      data=None,
      dv=None,
      within=None,
      subject=None,
      between=None,
      correction="auto",
      effsize="np2",
  ):
      """Mixed-design (split-plot) ANOVA.
  
      Parameters
      ----------
      data : :py:class:`pandas.DataFrame`
          DataFrame. Note that this function can also directly be used as a
          Pandas method, in which case this argument is no longer needed.
      dv : string
          Name of column containing the dependent variable.
      within : string
          Name of column containing the within-subject factor
          (repeated measurements).
      subject : string
          Name of column containing the between-subject identifier.
      between : string
          Name of column containing the between factor.
      correction : string or boolean
          If True, return Greenhouse-Geisser corrected p-value.
          If `'auto'` (default), compute Mauchly's test of sphericity to
          determine whether the p-values needs to be corrected.
      effsize : str
          Effect size. Must be one of 'np2' (partial eta-squared), 'n2'
          (eta-squared) or 'ng2'(generalized eta-squared).
  
      Returns
      -------
      aov : :py:class:`pandas.DataFrame`
          ANOVA summary:
  
          * ``'Source'``: Names of the factor considered
          * ``'ddof1'``: Degrees of freedom (numerator)
          * ``'ddof2'``: Degrees of freedom (denominator)
          * ``'F'``: F-values
          * ``'p-unc'``: Uncorrected p-values
          * ``'np2'``: Partial eta-squared effect sizes
          * ``'eps'``: Greenhouse-Geisser epsilon factor (= index of sphericity)
          * ``'p-GG-corr'``: Greenhouse-Geisser corrected p-values
          * ``'W-spher'``: Sphericity test statistic
          * ``'p-spher'``: p-value of the sphericity test
          * ``'sphericity'``: sphericity of the data (boolean)
  
      See Also
      --------
      anova, rm_anova, pairwise_tests
  
      Notes
      -----
      Data are expected to be in long-format (even the repeated measures).
      If your data is in wide-format, you can use the :py:func:`pandas.melt()`
      function to convert from wide to long format.
  
      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 :: If the between-subject groups are unbalanced (= unequal sample sizes),
          a type II ANOVA will be computed. Note however that SPSS, JAMOVI and JASP by default
          return a type III ANOVA, which may lead to slightly different results.
  
      Examples
      --------
      For more examples, please refer to the `Jupyter notebooks
      <https://github.com/raphaelvallat/pingouin/blob/master/notebooks/01_ANOVA.ipynb>`_
  
      Compute a two-way mixed model ANOVA.
  
      >>> from pingouin import mixed_anova, read_dataset
      >>> df = read_dataset('mixed_anova')
      >>> aov = mixed_anova(dv='Scores', between='Group',
      ...                   within='Time', subject='Subject', data=df)
      >>> aov.round(3)
              Source     SS  DF1  DF2     MS      F  p-unc    np2    eps
      0        Group  5.460    1   58  5.460  5.052  0.028  0.080    NaN
      1         Time  7.628    2  116  3.814  4.027  0.020  0.065  0.999
      2  Interaction  5.167    2  116  2.584  2.728  0.070  0.045    NaN
  
      Same but reporting a generalized eta-squared effect size. Notice how we
      can also apply this function directly as a method of the dataframe, in
      which case we do not need to specify ``data=df`` anymore.
  
      >>> df.mixed_anova(dv='Scores', between='Group', within='Time',
      ...                subject='Subject', effsize="ng2").round(3)
              Source     SS  DF1  DF2     MS      F  p-unc    ng2    eps
      0        Group  5.460    1   58  5.460  5.052  0.028  0.031    NaN
      1         Time  7.628    2  116  3.814  4.027  0.020  0.042  0.999
      2  Interaction  5.167    2  116  2.584  2.728  0.070  0.029    NaN
      """
      assert effsize in [
          "n2",
          "np2",
          "ng2",
      ], "effsize must be n2, np2 or ng2."
  
      # Check that only a single within and between factor are provided
      one_is_list = isinstance(within, list) or isinstance(
          between, list
      )
      both_are_str = isinstance(within, (str, int)) and isinstance(
          between, (str, int)
      )
      if one_is_list or not both_are_str:
          raise ValueError(
              "within and between factors must both be strings referring to a column in the data. "
              "Specifying multiple within and between factors is currently not supported. "
              "For more information, see: https://github.com/raphaelvallat/pingouin/issues/136"
          )
  
      # Check data
      data = _check_dataframe(
          dv=dv,
          within=within,
          between=between,
          data=data,
          subject=subject,
          effects="interaction",
      )
  
      # 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, between],
          columns=within,
          values=dv,
          observed=True,
      )
      data_piv = data_piv.dropna()
      data = data_piv.melt(
          ignore_index=False, value_name=dv
      ).reset_index()
  
      # Check that subject IDs do not overlap between groups: the subject ID
      # should have a unique range / set of values for each between-subject
      # group e.g. group1= 1 --> 20 and group2 = 21 --> 40.
      if not (
          data.groupby([subject, within], observed=True)[
              between
          ].nunique()
          == 1
      ).all():
          raise ValueError(
              "Subject IDs cannot overlap between groups: each "
              "group in `%s` must have a unique set of "
              "subject IDs, e.g. group1 = [1, 2, 3, ..., 10] "
              "and group2 = [11, 12, 13, ..., 20]" % between
          )
  
      # SUMS OF SQUARES
      grandmean = data[dv].mean(numeric_only=True)
      ss_total = ((data[dv] - grandmean) ** 2).sum()
      # Extract main effects of within and between factors
      aov_with = rm_anova(
          dv=dv,
          within=within,
          subject=subject,
          data=data,
          correction=correction,
          detailed=True,
      )
      aov_betw = anova(dv=dv, between=between, data=data, detailed=True)
      ss_betw = aov_betw.at[0, "SS"]
      ss_with = aov_with.at[0, "SS"]
      # Extract residuals and interactions
      grp = data.groupby(
          [between, within], observed=True, group_keys=False
      )[dv]
      # ssresall = residuals within + residuals between
      ss_resall = grp.apply(lambda x: (x - x.mean()) ** 2).sum()
      # Interaction
      ss_inter = ss_total - (ss_resall + ss_with + ss_betw)
      ss_reswith = aov_with.at[1, "SS"] - ss_inter
      ss_resbetw = ss_total - (
          ss_with + ss_betw + ss_reswith + ss_inter
      )
  
      # DEGREES OF FREEDOM
      n_obs = data.groupby(within, observed=True)[dv].count().max()
      df_with = aov_with.at[0, "DF"]
      df_betw = aov_betw.at[0, "DF"]
      df_resbetw = (
          n_obs
          - data.groupby(between, observed=True)[dv].count().count()
      )
      df_reswith = df_with * df_resbetw
      df_inter = aov_with.at[0, "DF"] * aov_betw.at[0, "DF"]
  
      # MEAN SQUARES
      ms_betw = aov_betw.at[0, "MS"]
      ms_with = aov_with.at[0, "MS"]
      ms_resbetw = ss_resbetw / df_resbetw
      ms_reswith = ss_reswith / df_reswith
      ms_inter = ss_inter / df_inter
  
      # F VALUES
      f_betw = ms_betw / ms_resbetw
      f_with = ms_with / ms_reswith
      f_inter = ms_inter / ms_reswith
  
      # P-values
      p_betw = f(df_betw, df_resbetw).sf(f_betw)
      p_with = f(df_with, df_reswith).sf(f_with)
      p_inter = f(df_inter, df_reswith).sf(f_inter)
  
      # Effects sizes (see Bakeman 2005)
      if effsize == "n2":
          # Standard eta-squared
          ef_betw = ss_betw / ss_total
          ef_with = ss_with / ss_total
          ef_inter = ss_inter / ss_total
      elif effsize == "ng2":
          # Generalized eta-square
          ef_betw = ss_betw / (ss_betw + ss_resall)
          ef_with = ss_with / (ss_with + ss_resall)
          ef_inter = ss_inter / (ss_inter + ss_resall)
      else:
          # Partial eta-squared (default)
          # ef_betw = f_betw * df_betw / (f_betw * df_betw + df_resbetw)
          # ef_with = f_with * df_with / (f_with * df_with + df_reswith)
          ef_betw = ss_betw / (ss_betw + ss_resbetw)
          ef_with = ss_with / (ss_with + ss_reswith)
          ef_inter = ss_inter / (ss_inter + ss_reswith)
  
      # Stats table
      aov = pd.concat(
          [aov_betw.drop(1), aov_with.drop(1)],
          axis=0,
          sort=False,
          ignore_index=True,
      )
      # Update values
      aov.rename(columns={"DF": "DF1"}, inplace=True)
      aov.at[0, "F"], aov.at[1, "F"] = f_betw, f_with
      aov.at[0, "p-unc"], aov.at[1, "p-unc"] = p_betw, p_with
      aov.at[0, effsize], aov.at[1, effsize] = ef_betw, ef_with
      aov_inter = pd.DataFrame(
          {
              "Source": "Interaction",
              "SS": ss_inter,
              "DF1": df_inter,
              "MS": ms_inter,
              "F": f_inter,
              "p-unc": p_inter,
              effsize: ef_inter,
          },
          index=[2],
      )
      aov = pd.concat(
          [aov, aov_inter], axis=0, sort=False, ignore_index=True
      )
      aov["DF2"] = [df_resbetw, df_reswith, df_reswith]
      aov["eps"] = [np.nan, aov_with.at[0, "eps"], np.nan]
      col_order = [
          "Source",
          "SS",
          "DF1",
          "DF2",
          "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 8 for calling a global function with example usage: mixed_anova(data, dv, within, subject, between, correction, effsize) and returns: _postprocess_dataframe