Interpreting results · Interpret a result

Cohen's d vs Hedges' g: which to report, and how much they differ

Hedges' g is Cohen's d multiplied by a small-sample correction J. With lab-sized groups in a single study, report g; a table of J by group size, one shared confidence interval, and Python and R code.

By Licklider · Published · Last reviewed · How this page was made · Markdown

On this page
  1. The only difference: one factor, J
  2. One interval for both
  3. Worked example from summary statistics
  4. Paired designs: say which d
  5. Glass’s Δ: when the control SD is the yardstick
  6. Small, medium, large: describe instead of label
  7. Combining studies is a different job
  8. What to write
  9. Check what an AI assistant ran
  10. References

Quick answer. Hedges’ g is Cohen’s d multiplied by a correction factor J (a number just below 1; 0.92 with 6 per group) that removes d’s upward bias in small samples. For a single study, report g: below about 20 per group the correction matters (g is 7.7% smaller than d at 6 per group); from 20 per group upwards the two differ by 2% or less, so either is defensible if you name it. d and g describe the same unknown standardised difference δ, so report one 95% confidence interval for δ, from the pooled-SD (Student’s) t statistic, beside them; an interval multiplied by J is not a 95% interval for δ. For paired data, say which d you used (d_z or d_av), because they can differ by a factor of two or more for the same change, and give an interval only for d_z. Report the difference in original units with its own interval first; a standardised effect comes second.

Terms used below. A standardised effect divides a difference by a standard deviation (SD), so it has no units. Cohen’s d divides the difference in means by the pooled SD of the two groups. Pooled SD combines both groups’ SDs, weighted by their degrees of freedom; it assumes the two groups share one SD. Hedges’ g is d multiplied by J, a number just below 1 that depends only on the degrees of freedom (df, here n₁ + n₂ − 2). Bias here means the tendency of d to overstate δ on average in small samples. δ (delta) is the true standardised difference: the value you would estimate with unlimited animals of the same kind; d and g estimate it. The noncentral t distribution is the distribution of the t statistic when there is a real effect; turning it round at your observed t gives the interval for δ. Original units are the measurement’s own units (U/L, grams); a difference in original units is an unstandardised effect. d_z divides the mean of paired differences by the SD of those differences; d_av divides it by the average of the two SDs. Glass’s Δ divides by the control group’s SD only. g_z is d_z multiplied by J with df = pairs − 1. Constructed data are values written for illustration, not measurements from a real experiment.

In five steps: (1) take the mean, SD and n of each group, one value per animal; (2) report the difference in units with its 95% CI from your t-test; (3) run the code below for d, J, g and the δ interval; (4) paste the “What to write” sentences; (5) for paired data, use the paired code and report d_z.

The only difference: one factor, J

Cohen’s d is biased upwards in small samples: on average it overstates δ. Hedges (1981) derived the exact correction, and Lakens (2013) gives a close approximation, J ≈ 1 − 3/(4(n₁ + n₂) − 9). Lakens concludes that although the difference is small “especially in sample sizes above 20”, “it is preferable (and just as easy) to report Hedges’s g” (Lakens 2013).

How much g shrinks d, with equal groups (exact J from the gamma function; the approximation is within 0.003 of it at every size shown):

Animals per group df J g is smaller than d by
3 4 0.798 20.2%
4 6 0.869 13.1%
5 8 0.903 9.7%
6 10 0.923 7.7%
8 14 0.945 5.5%
10 18 0.958 4.2%
15 28 0.973 2.7%
20 38 0.980 2.0%
30 58 0.987 1.3%
50 98 0.992 0.8%

The table is for equal groups; for unequal groups use df = n₁ + n₂ − 2 in the formula (4 vs 9 mice: df 11, J = 0.930). J does not depend on the data, only on the group sizes, so g and d always have the same sign and |g| ≤ |d|. Two details that trip readers up: g still uses the pooled SD (it is not a different standardiser), and equal group sizes do not make g equal to d.

What to do: for a single study, report g (it matters below about 20 per group), name it (“Hedges’ g, pooled SD”), and give the group sizes so a reader can recover d.

One interval for both

d and g are two estimates of the same δ, so they share one confidence interval: the interval for δ obtained by inverting the noncentral t distribution at the pooled-SD t statistic, the one from Student’s t-test (the “pivot” method). In plain terms: take the t from a Student’s t-test, find the δ values whose noncentral t distributions place that t in their central 95%, and those δ values form the interval. If your main test is Welch’s, keep Welch’s test for the p-value and the interval in units; the standardised interval still uses the pooled SD and assumes the two groups share one SD. When both groups are normal with a common SD, this interval covers δ 95% of the time by construction (Cumming & Finch 2001 explain the method).

In effectsize 0.8.6, hedges_g() multiplies those limits by J as well, so its printed “95%” interval covers δ less often than 95% (check your installed version; from effectsize 0.8.7 the documentation describes hedges_g() as an alias for cohens_d(adjust = TRUE)). Exact coverage of the J-scaled 95% interval, computed with the published example.py:

Animals per group True δ Coverage of J-scaled interval
3 1 93.5%
3 2 90.3%
6 1 94.6%
6 2 93.8%
6 3 93.2%
10 1 94.8%
20 1 94.9%

What to do: report one interval for δ beside d and g. If your software prints J-scaled limits for g, report the δ interval instead (in effectsize 0.8.6 it is the interval cohens_d() prints) and say which you used. If your software’s effect-size output (Prism, SPSS or another) does not say which SD and which interval it uses, compute them with the code on this page or the effect size calculator.

Worked example from summary statistics

Plasma ALT in 6 control and 6 treated mice (constructed data from the sample-size response guide, rounded as you would copy them from a table): control 47.17 U/L (SD 7.94), treated 58.17 U/L (SD 8.13).

Quantity Value
Difference in means 11.0 U/L
Pooled SD 8.04 U/L
Cohen’s d 1.37
J (df = 10) 0.923
Hedges’ g 1.26
95% CI for δ (noncentral t) 0.07 to 2.62
J-scaled limits printed by effectsize hedges_g() 0.06 to 2.42 (not a 95% interval for δ)

The interval is for δ and is the same for d and g, so g = 1.26 is not at its midpoint. The difference in units, from Welch’s t-test, is 11.0 U/L (95% CI 0.7 to 21.3). The standardised interval runs from almost no effect to a very large one: with 6 per group a standardised effect is imprecise whichever letter you use. That is why the difference in units with its own interval comes first (reviewer asks for effect sizes).

Python (SciPy):

import math
import numpy as np
from scipy import optimize, special, stats

m1, s1, n1 = 47.17, 7.94, 6   # control: mean, SD, n
m2, s2, n2 = 58.17, 8.13, 6   # treated
# from raw values instead: m1, s1, n1 = x.mean(), x.std(ddof=1), len(x)  (ddof=1 gives the sample SD)

df = n1 + n2 - 2
sp = math.sqrt(((n1 - 1) * s1**2 + (n2 - 1) * s2**2) / df)   # pooled SD
d = (m2 - m1) / sp
J = math.exp(special.gammaln(df / 2) - 0.5 * math.log(df / 2) - special.gammaln((df - 1) / 2))
g = J * d

# 95% CI for delta: invert the noncentral t at the observed pooled t (solved on |t|)
k = math.sqrt(1 / n1 + 1 / n2)
t = abs(d) / k
def F(lam):
    v = stats.nct.cdf(t, df, lam)
    return 0.0 if np.isnan(v) else v   # guards SciPy's NaN in far tails
lo = optimize.brentq(lambda L: F(L) - 0.975, t - 10, t + 10) * k
hi = optimize.brentq(lambda L: F(L) - 0.025, t - 10, t + 10) * k
if d < 0:
    lo, hi = -hi, -lo
print(f"d = {d:.2f}, J = {J:.3f}, g = {g:.2f}, 95% CI for delta {lo:.2f} to {hi:.2f}")

R (base):

m1 <- 47.17; s1 <- 7.94; n1 <- 6   # control: mean, SD, n
m2 <- 58.17; s2 <- 8.13; n2 <- 6   # treated
# from raw values instead: m1 <- mean(x); s1 <- sd(x); n1 <- length(x)

df <- n1 + n2 - 2
sp <- sqrt(((n1 - 1) * s1^2 + (n2 - 1) * s2^2) / df)   # pooled SD
d <- (m2 - m1) / sp
J <- exp(lgamma(df / 2) - 0.5 * log(df / 2) - lgamma((df - 1) / 2))
g <- J * d

# 95% CI for delta: invert the noncentral t at the observed pooled t (solved on |t|)
k <- sqrt(1 / n1 + 1 / n2)
t <- abs(d) / k
f <- function(lam, p) suppressWarnings(pt(t, df, ncp = lam)) - p  # pt can warn about precision
ci <- k * c(uniroot(f, c(t - 10, t + 10), p = 0.975)$root,
            uniroot(f, c(t - 10, t + 10), p = 0.025)$root)
if (d < 0) ci <- -rev(ci)
cat(sprintf("d = %.2f, J = %.3f, g = %.2f, 95%% CI for delta %.2f to %.2f\n", d, J, g, ci[1], ci[2]))

Both print d = 1.37, J = 0.923, g = 1.26, 95% CI for delta 0.07 to 2.62. The effect size calculator does the same from summary statistics in your browser.

What to do: compute d, J, g and the δ interval from your summary statistics with the code above, and check the result against your software’s output before you paste it.

Paired designs: say which d

For before–after or matched measurements, two standardised effects are in use, and they answer different questions:

  • d_z divides the mean change by the SD of the paired differences. It grows as the two measurements become more correlated.
  • d_av divides the mean change by the average of the two SDs (Lakens 2013, eq. 10). It ignores the correlation r between the measurements, so it stays comparable to an independent-groups d; it has no simple exact interval, so report it as a point estimate only.

For the same mean change (0.5) and the same SD of 1 at both time points, at different correlations:

Correlation r d_av d_z d_z ÷ d_av
0 0.50 0.35 0.71
0.3 0.50 0.42 0.85
0.5 0.50 0.50 1.00
0.7 0.50 0.65 1.29
0.8 0.50 0.79 1.58
0.9 0.50 1.12 2.24

The noncentral-t interval above applies to d_z (and g_z = J × d_z with df = number of pairs − 1). If a reviewer asks for an interval, report d_z with its interval and name it, because d_av’s sampling distribution depends on r. Paired code (constructed values for 6 mice; before and after must list the same mice in the same order).

Python (SciPy):

import math
import numpy as np
from scipy import optimize, special, stats

before = np.array([52.1, 47.3, 55.8, 49.0, 60.2, 51.5])  # one value per mouse, before treatment
after = np.array([58.4, 50.9, 63.0, 55.2, 64.1, 59.8])   # same mice, after

diff = after - before
n = len(diff)
df = n - 1
dz = diff.mean() / diff.std(ddof=1)                       # d_z: SD of the paired differences
J = math.exp(special.gammaln(df / 2) - 0.5 * math.log(df / 2) - special.gammaln((df - 1) / 2))
gz = J * dz

# 95% CI for delta_z: invert the noncentral t at the paired t (solved on |t|)
k = 1 / math.sqrt(n)
t = abs(dz) / k
def F(lam):
    v = stats.nct.cdf(t, df, lam)
    return 0.0 if np.isnan(v) else v   # guards SciPy's NaN in far tails
lo = optimize.brentq(lambda L: F(L) - 0.975, t - 10, t + 10) * k
hi = optimize.brentq(lambda L: F(L) - 0.025, t - 10, t + 10) * k
if dz < 0:
    lo, hi = -hi, -lo
print(f"mean change {diff.mean():.2f}, d_z = {dz:.2f}, g_z = {gz:.2f}, 95% CI for delta_z {lo:.2f} to {hi:.2f}")

R (base):

before <- c(52.1, 47.3, 55.8, 49.0, 60.2, 51.5)  # one value per mouse, before treatment
after  <- c(58.4, 50.9, 63.0, 55.2, 64.1, 59.8)  # same mice, after

diff <- after - before
n <- length(diff)
df <- n - 1
dz <- mean(diff) / sd(diff)                       # d_z: SD of the paired differences
J <- exp(lgamma(df / 2) - 0.5 * log(df / 2) - lgamma((df - 1) / 2))
gz <- J * dz

# 95% CI for delta_z: invert the noncentral t at the paired t (solved on |t|)
k <- 1 / sqrt(n)
t <- abs(dz) / k
f <- function(lam, p) suppressWarnings(pt(t, df, ncp = lam)) - p  # pt can warn about precision
ci <- k * c(uniroot(f, c(t - 10, t + 10), p = 0.975)$root,
            uniroot(f, c(t - 10, t + 10), p = 0.025)$root)
if (dz < 0) ci <- -rev(ci)
cat(sprintf("mean change %.2f, d_z = %.2f, g_z = %.2f, 95%% CI for delta_z %.2f to %.2f\n",
            mean(diff), dz, gz, ci[1], ci[2]))

Both print mean change 5.92, d_z = 3.21, g_z = 2.70, 95% CI for delta_z 1.12 to 5.28. The d_z here is large because the before and after values of each mouse are strongly correlated; d_av for the same data would be much smaller.

What to do: name the paired effect (“d_z, SD of the paired differences”), and give d_av as a point estimate only when readers will compare it with independent-groups studies.

Glass’s Δ: when the control SD is the yardstick

If the treatment changes the spread as well as the mean, dividing by a pooled SD mixes the two. Lakens (2013) writes: “Whenever standard deviations differ substantially between conditions, Glass’s Δ should be reported”. Glass’s Δ divides the difference by the control SD; in the example it is 11.0 / 7.94 = 1.39 (computed only to show the formula: the example’s SDs, 7.94 and 8.13, are nearly equal, so the pooled g is the better summary there). This page gives no interval for Δ; the δ interval above assumes one shared SD, so do not attach it to Δ.

What to do: report Glass’s Δ beside the difference in units when the spreads differ clearly, and decide which group is the reference before looking at the results.

Small, medium, large: describe instead of label

Cohen’s benchmarks (0.2, 0.5, 0.8) came from behavioural research. Lakens (2013) notes that “these values are arbitrary and should not be interpreted rigidly”, and that “the only reason to use these benchmarks is because findings are extremely novel, and cannot be compared to related findings in the literature” (citing Cohen 1988). A g of 1.26 in a 6-per-group mouse study, with an interval from 0.07 to 2.62, is compatible with anything from a negligible to a very large effect.

What to do: describe the effect in units your readers know (U/L, grams, fold change), and compare it with effects in related studies rather than with the benchmarks.

Combining studies is a different job

In a meta-analysis, the bias correction interacts with how each study’s variance is estimated. Lin and Aloe (2021) found in simulations that “the usual version of Hedges’ g can result in more biased meta-estimation than Cohen’s d”, and recommend average-adjusted variance estimators (Lin & Aloe 2021). They also note that books and software use the letters inconsistently.

What to do: for a single study, report g as above; for a meta-analysis, use a meta-analysis package and follow its documented estimator, citing it.

What to write

Methods sentence:

Effect sizes are reported as the difference in means with its 95% CI and as Hedges’ g (pooled SD, exact small-sample correction) with a 95% CI for the standardised difference δ obtained by inverting the noncentral t distribution.

Results sentence (two groups):

Treated mice had [11.0] U/L higher plasma ALT than controls (95% CI [0.7] to [21.3]; Welch’s t-test, t([9.99]) = [2.37], p = [0.039]); Hedges’ g = [1.26] (95% CI for δ [0.07] to [2.62]; n = [6] per group).

Results sentence (paired data, from the paired example above):

[Outcome] increased by [5.92] [units] after treatment (95% CI [3.98] to [7.85]; paired t-test, t([5]) = [7.86], p = [0.0005]); d_z = [3.21] (SD of the paired differences; 95% CI for δ_z [1.12] to [5.28]; n = [6] mice).

For a single study, report g with the δ interval; add d only if a reviewer or journal asks for it. For a meta-analysis, see combining studies.

What to do: copy the Methods sentence once, then report each comparison in the Results pattern, replacing every bracketed number with your own t-test’s result and your own g (or d_z) and δ interval. The bracketed numbers are the page’s constructed examples (template check).

Check what an AI assistant ran

Generated code mixes up these effects in predictable ways. Check four things in the code, not in the summary text:

  1. Which SD? sd(c(x, y)) or the SD of all values pooled together is not the pooled SD; the formula above weights each group’s variance by its df.
  2. Was J applied, and which J? Look for the gamma-function form or 1 − 3/(4(n₁ + n₂) − 9). If the code prints “g” but contains neither, it reported d.
  3. Which interval? If the interval for g is the d interval multiplied by J, report the unmultiplied interval for δ instead.
  4. Paired data: does it divide by the SD of the differences (d_z) or by the average of the two SDs (d_av)? Make the label match.

What to do: recompute one comparison by hand with the code on this page; if your number differs in the second decimal, find which of the four choices differs.

References

  • Hedges LV (1981). Distribution theory for Glass’s estimator of effect size and related estimators. Journal of Educational Statistics 6(2):107–128. doi:10.3102/10769986006002107
  • Lakens D (2013). Calculating and reporting effect sizes to facilitate cumulative science: a practical primer for t-tests and ANOVAs. Frontiers in Psychology 4:863. doi:10.3389/fpsyg.2013.00863
  • Cumming G, Finch S (2001). A primer on the understanding, use, and calculation of confidence intervals that are based on central and noncentral distributions. Educational and Psychological Measurement 61(4):532–574. doi:10.1177/0013164401614002
  • Lin L, Aloe AM (2021). Evaluation of various estimators for standardized mean difference in meta-analysis. Statistics in Medicine 40(2):403–426. doi:10.1002/sim.8781

How this page was made

  • Written and published by Licklider. Formulas and recommendations are cited to the peer-reviewed papers under References; quoted text was checked against the source.
  • Every number on this page comes from stored code (Python 3.13 with SciPy 1.18.1; R 4.3.3, with effectsize 0.8.6 for the software note), and the two languages agree.
  • Separate review passes checked the statistics, the citations and readability before publication.