The following R code calculates two effect sizes (Hedges’ g and ROM),
compares their distributions and heterogeneity, and performs
meta-analyses on the dat_ROM
dataset which includes
measurements of target-like use (see Foster
& Wigglesworth, 2016) as a percentage-based measure of accuracy
(e.g., of using past tense) in learners’ writing tasks between two
groups (treatment and control) at a post-test across experimental
studies.
As we shall see further below, ROM is preferred over Hedges’ g due to its less skewed distribution and smaller heterogeneity (\(I^2\)). A subsequent meta-analysis with ROM will then reveal that the treatment group shows a \(43.9\%\) improvement over the control group when interpreted via \(ROM\%\) (see manuscript). The following code describes all these steps.
The following R code loads the metafor
package, a tool
for conducting meta-analyses in R. It provides functions for calculating
effect sizes (escalc
) and performing statistical
analyses:
source("https://t.ly/TVmIg")
The next code calculates two types of effect sizes for each row in
dat_ROM
dataset that comes with the software. The output
will include natural-log-transformed Ratio of Means ("ROM"
)
and Hedges’ g ("SMD"
). Both effect sizes use means of
treatment and control groups (mT
, mC
),
standard deviations (sdT
, sdC
), and sample
sizes (n
) here being equal for the treatment and control
groups:
dat <- escalc(
data = dat_ROM, measure = "ROM", var.names = c("ROM", "v_ROM"),
m1i = mT,
m2i = mC,
sd1i = sdT,
sd2i = sdC,
n1i = n,
n2i = n)
dat <- escalc(
data = dat, measure = "SMD", var.names = c("g", "v_g"),
m1i = mT,
m2i = mC,
sd1i = sdT,
sd2i = sdC,
n1i = n,
n2i = n)
The var.names
parameter assigns new column names for the
calculated effect sizes (ROM
, g
) and their
sampling variances (v_ROM
, v_g
).
To understand the characteristics of the calculated effect sizes, histograms are created for both Hedges’ g and ROM. These plots show the distributions and help assess their suitability:
hist(dat$g, main = "Histogram of Hedges' g", xlab = "Hedges' g")
hist(dat$ROM, main = "Histogram of ROM", xlab = "ROM")
As shown above, the histogram for Hedges’ g shows much more skewness. But ROM tends to be less skewed, indicating a more stable and interpretable measure.
The next code performs random-effects meta-analyses on both Hedges’ g and ROM to calculate pooled effect sizes and heterogeneity (\(I^2\)):
# Meta-analysis for Hedges' g
g_meta <- rma(g, vi = v_g, data = dat)
# Meta-analysis for ROM
ROM_meta <- rma(ROM, vi = v_ROM, data = dat)
g_meta$I2 # I2 for Hedges' g
## [1] 74.95044
ROM_meta$I2 # I2 for ROM
## [1] 60.18319
As can be seen, the heterogeneity measure \(I^2\) (expressed in percentage) is larger for Hedges’ g. This supports the choice of ROM as the preferred effect size. Because when choice of effect size alone (a methodological decision) changes the amount of hetrogenity, such heterogeneity is likely artifactual rather than substantive.
The pooled ROM is interpreted as the percentage difference between
the treatment and control groups using a transformation function
(pct_dif_tran
).
post_rma(ROM_meta, tran = pct_dif_tran, type = "response")
## 1 Response SE Df Lower Upper z p-value Sig.
## 1 overall 43.880 2.325 Inf 39.395 48.511 22.512 0.000 ***
The post_rma()
function (see Norouzian
& Bui, 2024) applies the transformation
(pct_dif_tran
) to the ROM effect size (see manuscript).
This converts the pooled ROM into a percentage difference, making it
easier to interpret. Based on the output, the treatment groups performed
about \(43.9\%\) better than the
control groups.
The next R code is calculating within-group standardized mean change effect sizes for two groups (treatment and control), then combining these to compute the difference in effect sizes between the groups for use in a meta-analytic model. Here’s what each section of the code does.
source("https://t.ly/TVmIg")
Loads the metafor package, a tool for conducting meta-analyses in R.
It provides functions for calculating effect sizes (escalc
)
and performing statistical analyses. It also loads
dat_quasi
(see manuscript), a dataset used for
demonstrating DiD effect size.
datT <- escalc("SMCRP",
ni=n,
m1i=mpost,
m2i=mpre,
sd1i=sdpre,
sd2i=sdpost,
ri=r,
data=subset(dat_quasi, Group=="T"))
Purpose: Computes the within-group standardized mean
change effect size (SMCRP) for the treatment group.
ni
: Sample size of the group.
m1i
: Mean at post-test.
m2i
: Mean at pre-test.
sd1i
: Standard deviation at pre-test.
sd2i
: Standard deviation at post-test.
ri
: Correlation between pre-test and post-test
scores.
data=subset(dat_quasi, Group=="T")
: Filters
dat_quasi
to include only rows where the Group is “T”
(treatment group).
The result (datT
) includes two key outputs:
yi
: The calculated effect size for each study.
vi
: The variance of the effect size.
datC <- escalc("SMCRP",
ni=n,
m1i=mpost,
m2i=mpre,
sd1i=sdpre,
sd2i=sdpost,
ri=r,
data=subset(dat_quasi, Group=="C"))
Purpose: Same as above, but for the control group.
The subset is filtered for Group == "C"
(control
group).
dat <- data.frame(DiD = datT$yi - datC$yi,
vi = datT$vi + datC$vi,
time_interval = datT$time)
Purpose: Creates a new data frame that combines the
treatment and control effect sizes to calculate the DiD effect sizes.
DiD = datT$yi - datC$yi
: Computes the difference in
within-group effect sizes between the treatment and control groups.
vi = datT$vi + datC$vi
: Adds the variances of the treatment
and control groups to compute the variance of the between-group effect
size. time_interval = datT$time
: Copies the time interval
information from the treatment group.
The last R code adjusts the bias in effect size estimates (Hedges’ g) and specifically their sampling variability in studies that used assignment by intact classes, but failed to account for its effect in their analysis. Here’s a step-by-step explanation of the code.
source("https://t.ly/TVmIg")
The line above loads the custom functions g_cluster()
and g_vi_cluster()
from Norouzian & Bui (2024) 3m R
package. These functions adjust:
g_cluster()
: Hedges’ g effect size for intact class
assignment.
g_vi_cluster()
: The sampling variance of Hedges’ g for
intact class assignment.
Each adjustment function requires:
g
: Hedges’ g effect size estimate from the study.
n_cluster
: Total number of clusters (e.g.,
classrooms).
Nt
: Number of subjects in the treatment classes.
Nc
: Number of subjects in the control classes.
icc
: Intraclass correlation coefficient, defaulting to
0.15. This parameter reflects the similarity of outcomes within clusters
(e.g., students in the same classroom).
The dataset dat_note
(see manuscript) contains
meta-analysis data with:
Effect size (g
) and its variance
(v_g
).
Assignment type (assign_type
): whether groups were assigned
by student (individuals) or class (clusters).
Number of clusters (n_class
) and
Number of participants in treatment (Nt
) and control
(Nc
) classes.
group_by(dat_note, study) %>%
mutate(
g2 = ifelse(assign_type=="class", g_cluster(g, n_class, Nt, Nc), g),
v_g2 = ifelse(assign_type=="class", g_vi_cluster(g, n_class, Nt, Nc), v_g)
) %>% ungroup()
group_by(dat_note, study)
: Groups the data by study for
easier application of adjustments within each study.
mutate()
: Creates two new variables:
g2
: Adjusted Hedges’ g for studies with intact classes
(assign_type == "class"
). For studies with individual
randomization, the original g
is retained.
v_g2
: Adjusted variance for g
if clustering
was ignored.
ifelse
Conditions:
For assign_type == "class"
, apply g_cluster()
and g_vi_cluster()
for adjustments. Otherwise, retain the
original values (g
and v_g
).
ungroup()
: Removes grouping to return the final adjusted
dataset.
The adjustments are most noticeable in the sampling variances
(v_g2
), which become larger compared to the original values
(v_g
). This reflects the reduced precision due to the
clustering effect.