# Convert correlation r to Cohen's d (unequal groups of known size)

I am doing a meta-analysis. I would like to estimate Cohen's d for various studies. The correlation is made up of (a) a binary variable and (b) a numeric variable. I also know (a) the mean for the binary variable (i.e., I know how many people are in the two groups), and (b) The Pearson's correlation coefficient between the two variables. I want to estimate Cohen's d given this information.

I found this formula in Borenstein et al 2009:

r2d <- function(r) {
(2 * r) / sqrt(1 - r^2)
}


But it says:

"In applying this conversion we assume that the continuous data used to compute r has a bivariate normal distribution and that the two groups are created by dichotomizing one of the two variables." https://onlinelibrary.wiley.com/doi/book/10.1002/9780470743386

I assume that if I know the mean for the binary variable, I can get a more precise estimate of cohen's d from r.

What does the r to d formula look like if you know the mean of the binary variable?

The exact conversion of a point-biserial correlation coefficient (i.e., the correlation between a binary and a numeric/quantitative variable) to a Cohen's d value is: $$d = \frac{r \sqrt{h}}{\sqrt{1-r^2}},$$ where $$h = m/n_0 + m/n_1$$, $$m = n_0 + n_1 - 2$$, and $$n_0$$ and $$n_1$$ are the number of 0's and 1's respectively.

Here is some R code to demonstrate that this is exactly true:

x <- c(2,3,5,4,3,5,4,3,4,5)
d <- c(0,0,0,0,1,1,1,1,1,1)

# point-biserial correlation
r <- cor(x,d)
r

# convert point-biserial correlation to Cohen's d
m <- sum(table(d)) - 2
h <- sum(m / table(d))
r * sqrt(h) / sqrt(1 - r^2)

# compute Cohen's d from the means and SDs directly
means <- tapply(x, d, mean)
vars  <- tapply(x, d, var)
ns    <- table(d)
varp  <- ((ns[1]-1)*vars[1] + (ns[2]-1)*vars[2]) / (ns[1] + ns[2] - 2) # pooled variance
(means[2] - means[1]) / sqrt(varp)


Here is an an R function that implements his answer:

r2d <- function(r, p, n = 1000000) {
# r = correlation between binary variable and numeric variable
# p = proportion x == 1 on binary variable
# n = total sample size (default argument is large, because
#     results do not change much for n > 100
n1 <- round(p * n)
n0 <- n - n1
m <- n0 + n1 - 2
h <- m / n0 + m / n1
r * sqrt(h) /  sqrt(1 - r^2)

}


And here is a little table applying the formula to arrive at various d values for given r (rows) and p (columns) assuming a large sample size:

x <- expand.grid(r = seq(.1, .9, .1),
p = seq(.1, .5, .1))
x\$d <- apply(x, 1, function(X) r2d(r = X["r"], p = X["p"]))
round(reshape(x, idvar = "r", timevar = "p", direction = "wide"), 1)

r p=0.1 p=0.2 p=0.3 p=0.4 p=0.5
0.1   0.3   0.3   0.2   0.2   0.2
0.2   0.7   0.5   0.4   0.4   0.4
0.3   1.0   0.8   0.7   0.6   0.6
0.4   1.5   1.1   1.0   0.9   0.9
0.5   1.9   1.4   1.3   1.2   1.2
0.6   2.5   1.9   1.6   1.5   1.5
0.7   3.3   2.5   2.1   2.0   2.0
0.8   4.4   3.3   2.9   2.7   2.7
0.9   6.9   5.2   4.5   4.2   4.1