Home › Research Methodology › Post Hoc Tests Explained
Below, we explain post hoc tests step by step and run them live on real data from ScholarsColab.
Common post hoc tests at a glance
| Test | Use after | Notes |
|---|---|---|
| Tukey’s HSD | ANOVA with equal spreads | The most common choice; compares all pairs |
| Games-Howell | ANOVA with unequal spreads | Safer when group spreads differ |
| Bonferroni | Any set of comparisons | Simple and strict: multiply each p-value by the number of comparisons |
| Dunn’s test | Kruskal-Wallis | Pairwise comparisons of ranks |
| Dunnett’s test | ANOVA, comparing groups with one control | Fewer comparisons, more power |
Worked example: which venue groups differ in citations?
This continues the example from our ANOVA guide, where we found that citations differ between types of venue. Now we find out which types differ. Every result is calculated live, and you can run the same code yourself.
The data: 41,792 papers, mostly published between 1998 and 2026, by 967 ScholarsColab mentors (data updated 15 October 2026). The file you will load is anonymised: no paper titles, journal names or researcher identities.
Step 1: Load the data
import numpy as np
import pandas as pd
from datetime import date
# The ScholarsColab Research Methods Index (papers level): anonymised, updated daily
DATA = "https://scholarscolab.in/wp-json/scholarscolab/v1/research-methods-data?level=papers"
papers = pd.read_csv(DATA, comment="#") # lines starting with # hold the citation
def p_text(p):
return "< 0.001" if p < 0.001 else f"= {p:.3f}"
print(papers.shape)
papers.head()(41792, 15)
| year | citations | venue_type | venue_group | title_words | title_colon | review | systematic | machine_learning | deep_learning | iot | blockchain | covid | sustainability | discipline | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 2023.0 | 31 | journal | Other journals | 12 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 1 | 2024.0 | 24 | journal | Other journals | 13 | 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | Medicine & health |
| 2 | 2024.0 | 12 | journal | Other journals | 16 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 3 | 2024.0 | 9 | journal | Other journals | 20 | 0 | 1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
| 4 | 2024.0 | 9 | journal | Generic "International Journal of" | 9 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Medicine & health |
Step 2: Choose the papers and the groups
We use the same five venue groups and the same publication window as in the ANOVA example.
THIS_YEAR = date.today().year
# Compare papers that have had a similar time to collect citations
window = papers[papers["year"].between(THIS_YEAR - 16, THIS_YEAR - 4)].copy()
groups = ["IEEE Transactions / Journals", "Open-access mega-journals", "Other journals",
'Generic "International Journal of"', "Conference"]
window = window[window["venue_group"].isin(groups)]
summary = window.groupby("venue_group")["citations"].agg(papers="count", median="median", mean="mean")
summary.reindex(groups).round(1)| papers | median | mean | |
|---|---|---|---|
| IEEE Transactions / Journals | 252 | 69.5 | 120.2 |
| Open-access mega-journals | 813 | 34.0 | 60.6 |
| Other journals | 12173 | 9.0 | 47.3 |
| Generic "International Journal of" | 3253 | 4.0 | 14.8 |
| Conference | 4101 | 5.0 | 12.8 |
Step 3: Compare every pair, and correct for multiple testing
With five groups there are ten possible pairs. Because citations are skewed, we compare each pair with the Mann-Whitney U test. Running ten tests raises the chance of a false alarm, so the Bonferroni correction multiplies each p-value by ten.
from itertools import combinations
from scipy import stats
pairs = list(combinations(groups, 2))
rows = []
for a, b in pairs:
x = window.loc[window["venue_group"] == a, "citations"]
y = window.loc[window["venue_group"] == b, "citations"]
u, p = stats.mannwhitneyu(x, y, alternative="two-sided")
rows.append({"pair": f"{a} vs {b}", "median A": x.median(), "median B": y.median(),
"p": p, "p (Bonferroni)": min(1, p * len(pairs))})
result = pd.DataFrame(rows).set_index("pair")
result["significant"] = result["p (Bonferroni)"] < 0.05
result.round(4)| median A | median B | p | p (Bonferroni) | significant | |
|---|---|---|---|---|---|
| IEEE Transactions / Journals vs Open-access mega-journals | 69.5 | 34.0 | 0.0000 | 0.0000 | True |
| IEEE Transactions / Journals vs Other journals | 69.5 | 9.0 | 0.0000 | 0.0000 | True |
| IEEE Transactions / Journals vs Generic "International Journal of" | 69.5 | 4.0 | 0.0000 | 0.0000 | True |
| IEEE Transactions / Journals vs Conference | 69.5 | 5.0 | 0.0000 | 0.0000 | True |
| Open-access mega-journals vs Other journals | 34.0 | 9.0 | 0.0000 | 0.0000 | True |
| Open-access mega-journals vs Generic "International Journal of" | 34.0 | 4.0 | 0.0000 | 0.0000 | True |
| Open-access mega-journals vs Conference | 34.0 | 5.0 | 0.0000 | 0.0000 | True |
| Other journals vs Generic "International Journal of" | 9.0 | 4.0 | 0.0000 | 0.0000 | True |
| Other journals vs Conference | 9.0 | 5.0 | 0.0000 | 0.0000 | True |
| Generic "International Journal of" vs Conference | 4.0 | 5.0 | 0.2331 | 1.0000 | False |
How to choose and run a post hoc test
- Run the overall test first (ANOVA or Kruskal-Wallis).
- Choose the post hoc test that matches it and your data (see the table above).
- Decide which comparisons you need: all pairs, or only each group against a control.
- Report adjusted p-values and the size of each difference.
- Present results clearly, for example with letters or a table showing which groups differ.
Common mistakes reviewers point out
- Running many unadjusted t-tests instead of a proper post hoc test.
- Using a post hoc test that does not match the overall test or the data.
- Reporting only “significant” pairs without the differences themselves.
- Running post hoc tests after a non-significant overall test and reporting chance findings.
Frequently asked questions
What is a post hoc test?
A post hoc test compares groups pairwise after a significant ANOVA or Kruskal-Wallis test, to identify which groups differ, while controlling for the extra risk of testing many pairs.
Why do we need to adjust p-values?
Every test has a small chance of a false positive. When many tests are run, those chances add up, so adjustments keep the overall false-positive rate near 5%.
What is the Bonferroni correction?
It multiplies each p-value by the number of comparisons (or divides the significance level by it). It is simple and strict.
Which post hoc test should I use after ANOVA?
Tukey’s HSD is the usual choice when group spreads are similar; Games-Howell is safer when they differ; Dunnett’s test suits comparisons with a single control group.
Which post hoc test follows Kruskal-Wallis?
Dunn’s test is the most common, or pairwise Mann-Whitney U tests with a correction such as Bonferroni.
Use this data in your own work
ScholarsColab (2026). ScholarsColab Research Methods Index [Data set]. Vidhilekha Soft Solutions Pvt Ltd. Retrieved 15 October 2026, from https://scholarscolab.in/research-methodology/. Licensed under CC BY 4.0.Download the data (CSV) →Need help applying this to your research?
Discuss your research problem with a PhD mentor, hand the whole project to a research project manager, or post your project and let matched experts apply.
Mentors whose published work uses this approach:
- VV K BairagiPune University 1 related paper · View profile →
Roseline Oluwaseun OgundokunRedeemer's University Ede, Osun State1 related paper · View profile →
Dr. Vijay Vir SinghNoida International University, Greater Noida1 related paper · View profile →
Ferdib-Al-IslamDepartment of Computer Science and Engineering, Northern University of Business and Technology Khulna, Bangladesh1 related paper · View profile →
