diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/test_ch13_fitness.py b/tests/test_ch13_fitness.py new file mode 100644 index 0000000..3ca3597 --- /dev/null +++ b/tests/test_ch13_fitness.py @@ -0,0 +1,23 @@ +import statsmodels.formula.api as smf +from scripts import sim_fitness_2x2 as sim + +SEED = 2025 + +def test_fitness_mixed_model_signals(): + subjects, long_df = sim.simulate(n_per_group=5, seed=SEED) + + # Mixed model with random intercept for id, categorical time/group + covariates + md = smf.mixedlm( + "strength ~ C(time) * C(group) + age + sex + bmi", + long_df, + groups=long_df["id"], + ) + res = md.fit(reml=True) + + # main pre->post should be positive and clearly significant + assert res.params["C(time)[T.post]"] > 5 + assert res.pvalues["C(time)[T.post]"] < 1e-6 + + # interaction should be positive (ProgramB a bit more improvement); allow modest p + assert res.params["C(time)[T.post]:C(group)[T.ProgramB]"] > 0 + assert res.pvalues["C(time)[T.post]:C(group)[T.ProgramB]"] < 0.2 \ No newline at end of file diff --git a/tests/test_ch13_stroop.py b/tests/test_ch13_stroop.py new file mode 100644 index 0000000..98172f9 --- /dev/null +++ b/tests/test_ch13_stroop.py @@ -0,0 +1,35 @@ +import numpy as np +import pandas as pd +from scipy import stats +import statsmodels.formula.api as smf + +from scripts import sim_stroop + +SEED = 2025 + +def test_stroop_effect_and_mixed_model(): + subjects, trials = sim_stroop.simulate(n_subjects=6, n_trials=10, seed=SEED) + + # subject-level means by condition (ms) + means = ( + trials[trials["correct"]] + .query("rt_ms.between(200, 2000)") + .groupby(["subject", "condition"], as_index=False)["rt_ms"] + .mean() + .pivot(index="subject", columns="condition", values="rt_ms") + .dropna() + ) + diff = (means["incongruent"] - means["congruent"]) + # expect a solid Stroop effect around ~100ms on this seed; allow wide but positive range + assert diff.mean() > 60 and diff.mean() < 140 + + # mixed model on log RT with random intercept for subject + df = trials[trials["correct"] & trials["rt_ms"].between(200, 2000)].copy() + df["log_rt"] = np.log(df["rt_ms"]) + # Use categorical for condition + md = smf.mixedlm("log_rt ~ C(condition)", df, groups=df["subject"]) + res = md.fit(reml=False) + coef = res.params.get("C(condition)[T.incongruent]") + pval = res.pvalues.get("C(condition)[T.incongruent]") + assert 0.12 < coef < 0.22 + assert pval < 1e-6 \ No newline at end of file