[1] 924
Lecture 07 - Blocking and Clustering
age
, in our case)Source: Blair et al (2023)
\[ATE = \frac{1}{N}\sum_{i=1}^N y_{i,1} - y_{i,0}\]
\[ATE = \frac{1}{J}\sum_{j=1}^J\sum_{i=1}^{N_j} \frac{y_{i,1} - y_{i,0}}{N_j} = \sum_{j=1}^J \frac{N_j}{N}ATE_j\]
\[\widehat{ATE} = \sum_{j=1}^J \frac{N_j}{N}\widehat{ATE_j}\]
set.seed(12345)
# We have 10 units
N <- 10
# y0 is the potential outcome under control
y0 <- c(0, 0, 0, 1, 1, 3, 4, 5, 190, 200)
# For each unit, the treatment effect is intrinsic
tau <- c(10, 30, 200, 90, 10, 20, 30, 40, 90, 20)
# y1 is the potential outcome under treatment
y1 <- y0 + tau
# Two blocks: a and b
block <- c("a", "a", "a", "a", "a", "a", "b", "b", "b", "b")
# Z is the treatment assignment
# (in the code we use Z instead of T)
Z <- c(0, 0, 0, 0, 1, 1, 0, 0, 1, 1)
# Y is the observed outcome
Y <- Z * y1 + (1 - Z) * y0
# The data
dat <- data.frame(Z = Z, y0 = y0, y1 = y1, tau = tau, b = block, Y = Y)
head(dat)
Z y0 y1 tau b Y
1 0 0 10 10 a 0
2 0 0 30 30 a 0
3 0 0 200 200 a 0
4 0 1 91 90 a 1
5 1 1 11 10 a 11
6 1 3 23 20 a 23
Estimate Std. Error t value Pr(>|t|) CI Lower CI Upper DF
(Intercept) 1.666667 0.9189366 1.813691 0.10728314 -0.4524049 3.785738 8
Z 131.833333 68.4173061 1.926900 0.09015082 -25.9372575 289.603924 8
Estimate Std. Error t value Pr(>|t|) CI Lower CI Upper DF
(Intercept) -32.42857 21.63212 -1.499093 0.17752759 -83.58042 18.72327 7
Z 114.78571 50.53715 2.271314 0.05736626 -4.71565 234.28708 7
blockb 102.28571 50.49783 2.025547 0.08245280 -17.12268 221.69411 7
How are they different? (The first one ignores the blocks. The second one uses a different set of weights, created using fixed effects variables or indicator/dummy variables)
And we can estimate the total ATE by adjusting the weights according to the size of the blocks:
Estimate Std. Error t value Pr(>|t|) CI Lower CI Upper DF
(Intercept) 1.95 0.250000 7.800000 0.0002340912 1.338272 2.561728 6
Z 108.25 12.530862 8.638672 0.0001325490 77.588086 138.911914 6
blockb_c 4.25 0.559017 7.602631 0.0002696413 2.882135 5.617865 6
Z:blockb_c 228.75 30.599224 7.475680 0.0002957945 153.876397 303.623603 6
Source: DeclareDesign (2018)
Source: TMG Research
:::
Source: Patterson et al (2022)
:::
Aspect | Blocking | Clustering |
---|---|---|
Purpose | To reduce variance and increase precision | Practical necessity, not choice |
Unit of randomisation | Individual units | Groups of units |
Grouping | Based on pre-treatment characteristics | Based on natural or administrative groups |
Analysis | Compare within blocks, then weight | Must account for within-cluster similarity |
Example | Block by age, then randomise individuals within age groups | Randomise schools, but measure student outcomes |
Imagine we’re studying student test scores in 10 schools with 30 students each:
This means 25% of the total variance in test scores is due to differences between schools, and 75% is due to differences between students within the same school
Clustering reduces the number of possible treatment assignments, which reduces statistical information
With 10 individuals (5 with black hair, 5 with other colors):
Individual Randomisation:
Cluster Randomisation:
All individuals in a cluster receive the same treatment
Only 2 possible assignments:
The more clustered our design, the fewer possible randomisation combinations we have, leading to less statistical information for estimating treatment effects
This is why clustered designs typically require larger sample sizes to achieve the same statistical power as individually randomised experiments
Source: Stata Guide
\[DEFF = 1 + (m - 1) \times \rho\]
Where \(m\) = average cluster size and \(\rho\) = intra-cluster correlation (ICC)
DEFF = 1: Clustering has no effect on variance (\(\rho = 0\))
DEFF > 1: Clustering increases variance; need larger sample size
DEFF < 1: Clustering decreases variance (rare)
This means we need nearly 4 times as many observations as in a simple random sample to achieve the same statistical power!
When dealing with clustered data, we need to adjust our standard errors to account for the within-cluster correlation
Classical standard errors assume independent observations
In clustered data, observations within clusters are correlated
This leads to underestimated standard errors and inflated Type I error rates
Solution: Robust Clustered Standard Errors
estimatr
package in Rlibrary(estimatr)
# Simulate clustered data
set.seed(123)
n_clusters <- 20
n_per_cluster <- 30
total_n <- n_clusters * n_per_cluster
# Create cluster IDs
cluster_id <- rep(1:n_clusters, each = n_per_cluster)
# Treatment assigned at cluster level
treatment <- rep(rbinom(n_clusters, 1, 0.5), each = n_per_cluster)
# Create outcome with cluster effects
cluster_effect <- rnorm(n_clusters, 0, 2)
individual_effect <- rnorm(total_n, 0, 1)
outcome <- 2 * treatment + rep(cluster_effect, each = n_per_cluster) + individual_effect
# Create data frame
data <- data.frame(
cluster_id = factor(cluster_id),
treatment = treatment,
outcome = outcome
)
# Compare standard errors
model_naive <- lm_robust(outcome ~ treatment, data = data)
model_clustered <- lm_robust(outcome ~ treatment, clusters = cluster_id, data = data)
# Display results
summary(model_naive)
Call:
lm_robust(formula = outcome ~ treatment, data = data)
Standard error type: HC2
Coefficients:
Estimate Std. Error t value Pr(>|t|) CI Lower CI Upper DF
(Intercept) 0.4872 0.1239 3.932 9.397e-05 0.2439 0.7305 598
treatment 0.7484 0.1737 4.308 1.927e-05 0.4072 1.0896 598
Multiple R-squared: 0.02962 , Adjusted R-squared: 0.02799
F-statistic: 18.56 on 1 and 598 DF, p-value: 1.927e-05
Call:
lm_robust(formula = outcome ~ treatment, data = data, clusters = cluster_id)
Standard error type: CR2
Coefficients:
Estimate Std. Error t value Pr(>|t|) CI Lower CI Upper DF
(Intercept) 0.4872 0.6400 0.7613 0.4683 -0.9886 1.963 8.00
treatment 0.7484 0.8941 0.8370 0.4140 -1.1361 2.633 17.22
Multiple R-squared: 0.02962 , Adjusted R-squared: 0.02799
F-statistic: 0.7006 on 1 and 19 DF, p-value: 0.413
We can improve the efficiency of clustered designs by incorporating blocking at a higher level
R
with the estimatr
package