# Computing sample sizes from confidence intervals around Cohen's d

Is there a way how to compute sample size from Cohen's d and 95% confidence intervals (it's useful for instance for getting sample sizes from forest plots)?

From How do you calculate confidence intervals for Cohen's d?, it's possible to see that confidence intervals are dependent on sample sizes of both samples, but it is okay for me to assume that the sample sizes are equal.

If there is a way how to do this in R, that would be even better.

Yes, this is certainly possible. Let $d$ be the observed Cohen's d value based on a sample size of $n_1$ and $n_2$ individuals in the two groups. Then an approximate 95% confidence interval is often computed with $$d \pm 1.96 \sqrt{Var[d]},$$ where $$Var[d] = \frac{1}{n_1} + \frac{1}{n_2} + \frac{d^2}{2(n_1 + n_2)}.$$ Let $LB$ and $UB$ denote the lower and upper confidence interval bounds obtained in this manner.

Now if you are willing to assume that $n_1 = n_2 = n$, then $$Var[d] = \frac{8 + d^2}{4n}.$$ This implies that $$n = \frac{8 + d^2}{4 Var[d]}.$$ And since $$(UB - LB)^2 / (2\times1.96)^2 = Var[d],$$ we get $$n = \frac{(8 + d^2)(2 \times 1.96)^2}{4(UB - LB)^2}.$$

Let's try this out with R, using the metafor package for the computation of the CI.

library(metafor)

n <- 25 ### sample size of group 1 and group 2

dat <- escalc("SMD", m1i=10.8, sd1i=2.5, n1i=n, m2i=9.3, sd2i=2.2, n2i=n)
dat <- summary(dat)
dat


This yields:

      yi     vi    sei     zi  ci.lb  ci.ub
1 0.6270 0.0839 0.2897 2.1642 0.0592 1.1948


Here, yi is the d-value (with bias correction) and ci.lb and ci.ub are the confidence interval bounds. Suppose this is all that we know. Then:

c(with(dat, (8 + yi^2) * (2 * 1.96)^2 / (4 * (ci.ub - ci.lb)^2)))


yields:

[1] 25.00092


The slight discrepancy is due to using 1.96 and not qnorm(.975) for the exact 97.5th quantile of a standard normal distribution. But in practice, the d value and CI bounds will only be given to a few decimals, so the sample size obtained in this manner won't be exact anyway. It should be fairly close though. For example, if results are reported to two decimals, then:

c(with(dat, (8 + round(yi,2)^2) * (2 * qnorm(.975))^2 / (4 * (round(ci.ub,2) - round(ci.lb,2))^2)))


yields:

[1] 25.26145


So, just round the value obtained.