class_docstr: Test parametric.py.
class_docstr_tok: ["Test","parametric.py","."]
docstr: Test function anova.
  Compare with JASP and ezANOVA.
docstr_tok: ["Test","function","anova",".","Compare","with","JASP","and","ezANOVA","."]
code: def test_mixed_anova(self):
      """Test function anova.
      Compare with JASP and ezANOVA.
      """
      # trigger error when specifying more than one within or between factor
      with pytest.raises(ValueError, match="/pingouin/issues/136"):
          mixed_anova(
              dv="Scores",
              within=["Time"],
              subject="Subject",
              between="Group",
              data=df,
          )
  
      # Balanced design, two groups, three within factors
      aov = mixed_anova(
          dv="Scores",
          within="Time",
          subject="Subject",
          between="Group",
          data=df,
          correction=True,
      ).round(5)
      array_equal(aov.loc[:, "SS"], [5.45996, 7.62843, 5.16719])
      array_equal(aov.loc[:, "DF1"], [1, 2, 2])
      array_equal(aov.loc[:, "DF2"], [58, 116, 116])
      array_equal(aov.loc[:, "F"], [5.05171, 4.02739, 2.72800])
      array_equal(aov.loc[:, "np2"], [0.08012, 0.06493, 0.04492])
      assert (
          round(aov.at[1, "eps"], 3) == 0.999
      )  # Pingouin = 0.99875, JAMOVI = 0.99812
      assert (
          round(aov.at[1, "W-spher"], 3) == 0.999
      )  # Pingouin = 0.99875, JAMOVI = 0.99812
      assert round(aov.at[1, "p-GG-corr"], 2) == 0.02
      # With categorical: should be the same
      aov = mixed_anova(
          dv="Scores",
          within="Time",
          subject="Subject",
          between="Group",
          data=df_cat,
          correction=True,
      ).round(5)
      array_equal(aov.loc[:, "SS"], [5.45996, 7.62843, 5.16719])
      array_equal(aov.loc[:, "DF1"], [1, 2, 2])
      array_equal(aov.loc[:, "DF2"], [58, 116, 116])
      array_equal(aov.loc[:, "F"], [5.05171, 4.02739, 2.72800])
      array_equal(aov.loc[:, "np2"], [0.08012, 0.06493, 0.04492])
      assert (
          round(aov.at[1, "eps"], 3) == 0.999
      )  # Pingouin = 0.99875, JAMOVI = 0.99812
      assert (
          round(aov.at[1, "W-spher"], 3) == 0.999
      )  # Pingouin = 0.99875, JAMOVI = 0.99812
      assert round(aov.at[1, "p-GG-corr"], 2) == 0.02
  
      # Same with different effect sizes (compare with JAMOVI)
      aov = mixed_anova(
          dv="Scores",
          within="Time",
          subject="Subject",
          between="Group",
          data=df,
          effsize="n2",
      ).round(5)
      array_equal(aov.loc[:, "n2"], [0.02862, 0.03998, 0.02708])
      aov = mixed_anova(
          dv="Scores",
          within="Time",
          subject="Subject",
          between="Group",
          data=df,
          effsize="ng2",
      ).round(5)
      array_equal(aov.loc[:, "ng2"], [0.03067, 0.04234, 0.02908])
  
      # With missing values
      df_nan2 = df_nan.copy()
      df_nan2.iloc[158, 0] = np.nan
      aov = mixed_anova(
          dv="Scores",
          within="Time",
          subject="Subject",
          between="Group",
          data=df_nan2,
          correction=True,
      ).round(3)
      array_equal(aov.loc[:, "F"], [5.692, 3.054, 3.502])
      array_equal(aov.loc[:, "np2"], [0.094, 0.053, 0.060])
      assert aov.at[1, "eps"] == 0.997
      assert aov.at[1, "W-spher"] == 0.996
  
      # Unbalanced group
      df_unbalanced = df[df["Subject"] <= 54]
      aov = mixed_anova(
          data=df_unbalanced,
          dv="Scores",
          subject="Subject",
          within="Time",
          between="Group",
          correction=True,
      ).round(3)
      array_equal(aov.loc[:, "F"], [3.561, 2.421, 1.828])
      array_equal(aov.loc[:, "np2"], [0.063, 0.044, 0.033])
      assert aov.at[1, "eps"] == 1.0  # JASP = 0.998
      assert aov.at[1, "W-spher"] == 1.0  # JASP = 0.998
  
      # With three groups and four time points, unbalanced (JASP -- type II)
      df_unbalanced = read_dataset("mixed_anova_unbalanced.csv")
      aov = mixed_anova(
          data=df_unbalanced,
          dv="Scores",
          subject="Subject",
          correction=True,
          within="Time",
          between="Group",
      ).round(4)
      array_equal(aov.loc[:, "DF1"], [2, 3, 6])
      array_equal(aov.loc[:, "DF2"], [23, 69, 69])
      array_equal(aov.loc[:, "F"], [2.3026, 1.7071, 0.8877])
      array_equal(aov.loc[:, "p-unc"], [0.1226, 0.1736, 0.5088])
      array_equal(aov.loc[:, "np2"], [0.1668, 0.0691, 0.0717])
      # Check correction: values are very slightly different than ezANOVA
      assert np.isclose(aov.at[1, "eps"], 0.9254, atol=0.01)
      assert np.isclose(aov.at[1, "p-GG-corr"], 0.1779, atol=0.01)
      assert np.isclose(aov.at[1, "W-spher"], 0.8850, atol=0.01)
      assert np.isclose(aov.at[1, "p-spher"], 0.7535, atol=0.1)
  
      # Same but with different effect sizes
      aov = mixed_anova(
          data=df_unbalanced,
          dv="Scores",
          subject="Subject",
          within="Time",
          between="Group",
          effsize="n2",
      ).round(4)
      array_equal(aov.loc[:, "n2"], [0.0332, 0.0516, 0.0537])
      aov = mixed_anova(
          data=df_unbalanced,
          dv="Scores",
          subject="Subject",
          within="Time",
          between="Group",
          effsize="ng2",
      ).round(4)
      array_equal(aov.loc[:, "ng2"], [0.0371, 0.0566, 0.0587])
  
      # With overlapping subject IDs in the between-subject groups
      df_overlap = df.copy()
      df_overlap["Subject"] = df_overlap.groupby(
          ["Group"], group_keys=False
      )["Subject"].apply(lambda x: x - x.min())
      with pytest.raises(ValueError):
          mixed_anova(
              dv="Scores",
              within="Time",
              subject="Subject",
              between="Group",
              data=df_overlap,
          )
  
      df_overlap = df.copy()
      df_overlap["Subject"] = df_overlap["Subject"].replace(57, 3)
      with pytest.raises(ValueError):
          mixed_anova(
              dv="Scores",
              within="Time",
              subject="Subject",
              between="Group",
              data=df_overlap,
          )
  
file_path: pingouin/pingouin/tests/test_parametric.py
imports: import pytest
  import numpy
  from unittest import TestCase
  from numpy.testing import assert_array_equal
  from pingouin import read_dataset
  from pingouin.parametric import ttest, anova, rm_anova, mixed_anova, ancova, welch_anova
label_desc: Use image node_id 6 for calling the TestParametric obj's underlying member method code with example usage: obj.test_mixed_anova() without return types