Converting Cohen's $d$ to Pearson's $r$ $\ne$ calculated Pearson's $r$ I was calculating effect sizes for an analysis and noticed by chance that Pearson's $r$ calculated from Cohen's $d$ with a conversion formula is not the same as when I calculate the correlation given the raw data. Does anyone have an idea why it is like this? I've tried with random numbers several times and the two $r$'s are not even close, I've also tried to calculate manually and looked up which formulas are used by the packages (so this does not seem like a problem with the package), I can't make sense of this.
np.random.seed(10)    
df = pd.DataFrame(np.random.randint(0,100,size=(100, 2)), columns=list('AB'))
d = pg.compute_effsize(df['A'],df['B'], paired=False, eftype='cohen')
r_calc = pg.compute_effsize(df['A'],df['B'], paired=False, eftype='r')
r_conv = pg.convert_effsize(d,'cohen','r')

EDIT: The formulas I tried for $d$ are $d = \frac{\bar{x}_{1} - \bar{x}_{2}}{s}$.
With $s = \sqrt{\frac{(n_1 - 1)s^2_1 + (n_2 - 1)s^2_2}{n_1 + n_2 - 2}}$, or $s = \sqrt{\frac{(n_1 - 1)s^2_1 + (n_2 - 1)s^2_2}{n_1 + n_2}}$.
(pg.compute_effsize uses the first version with -2 in the denominator).
I get $d = 0,206012$ (or $0,207049$ for the second formula) and $r = 0,1029749$ when I convert $d$ with the formula used by pg.convert_effsize
$r = \frac{d}{\sqrt{d^2 + \frac{(n_x + n_y)^2 - 2(n_x+ n_y)}{n_x n_y}}}$
(using the alternative $d$, I get $r = 0,103488$).
When I calculate $r$ as the Pearson correlation, I get $0,157920$.
This was already asked here but not answered unfortunately:
Why does Pearson's $r$ differ from the converted value of $r$ from Cohen's $d$

The comment by @mdewey is the answer:

The formula for $r$ from $d$ gives you the point bi-serial correlation not Pearson's correlation coefficient.

To derive $r$ from $d$, compute the point-biserial correlation $r_{\operatorname{pb}}$ instead of the Pearson correlation coefficient $r_{\operatorname{pearson}}$ and use the bias correction term $\sqrt{(N-2)/N}$.
As an aside, the pingouin documentation is lacking since it doesn't define $r$ clearly. Cofusingly, the $r$ in pingouin.compute_effsize is not the same as the $r$ in pingouin.convert_effsize.
import numpy as np
import pingouin as pg

nx = ny = 100

np.random.seed(1234)

x = np.random.randint(0, 100, nx)
y = np.random.randint(0, 100, ny)

Compute summary statistics necessary to do the calculation by hand.
# Sample means and sums of squares for the two groups separately
xbar, ybar = np.mean(x), np.mean(y)
SSx, SSy = np.sum((x - xbar)**2), np.sum((y - ybar)**2)
SSxy = np.sum((x - xbar) * (y - ybar))

# The overall sample mean and sum of squares assume
# that the two samples come from the same population
mean = (nx * xbar + ny * ybar) / (nx + ny)
SS = np.sum((x - mean)**2) + np.sum((y - mean**2)

bias_correction = np.sqrt((nx + ny - 2) / (nx + ny))

In general Pearson's correlation coefficient is not equal to the point-biserial correlation.
# Same as np.corrcoef(x, y)[0, 1]
r_pearson = SSxy / np.sqrt(SSx * SSy)
r_pearson
#> 0.07740094

r_pb = (xbar - ybar) / np.sqrt(SS / (nx + ny)) * np.sqrt(nx * ny) / (nx + ny)
r_pb
#> 0.06503982

The point-biserial correlation is the Pearson correlation between the two samples $x$ and $y$ concatenated into one and a binary indicator variable for group membership.
np.corrcoef(np.concatenate([y, x]), np.repeat([0, 1], [ny, nx]))
#> array([[1.        , 0.06503982],
#>       [0.06503982, 1.        ]])

Now that we know the difference between Pearson's correlation and point-biserial correlation, we are ready to convert Cohen's $d$ to $r_{\operatorname{pb}}$ and vice versa. Note: We reverse the bias correction applied to Cohen's $d$, so that the converted effect sizes are equal to the input effect sizes.
d = pg.compute_effsize(
    x, y,
    eftype="cohen"
)
d
#> 0.13035565
#> 0.07740094
r = pg.compute_effsize(
    x, y,
    eftype="r"
)
r

d = d / bias_correction

d_to_r = pg.convert_effsize(
    d,
    "cohen", "r"
)
r_to_d = pg.convert_effsize(
    r_pb,
    "r", "cohen"
)
r_pb, d_to_r
#> (0.06503982, 0.06503982)
d, r_to_d
#> (0.13035565, 0.13035565)

