As a quick update to the excellent answer by @RobertLong, I simulated some data in Stata to demonstrate how a predictor that itself has sizable between-cluster variance increases the between-cluster variance in the outcome.
Here are the TLDR results. I simulated x1 so that it has almost no between-school variability whereas x2 was simulated to have a fair bit of it. Notice how in column 2 the sd(school) remains almost the same as in column 1. Contrastingly, in columns 3 and 4, the sd(school) increases substantially relative to column1.
----------------------------------------------------------------
(1) (2) (3) (4)
y y y y
----------------------------------------------------------------
x2 1.592 0.976
(0.0685) (0.0740)
x1 2.342 1.480
(0.0904) (0.100)
_cons 15.44 11.14 7.478 7.769
(0.167) (0.237) (0.537) (0.414)
----------------------------------------------------------------
sd(school) 0.763 0.758 3.034 2.045
(0.185) (0.146) (0.338) (0.260)
----------------------------------------------------------------
sd(residual) 4.041 3.242 3.054 2.876
(0.0927) (0.0744) (0.0703) (0.0666)
----------------------------------------------------------------
N 1000 1000 1000 1000
----------------------------------------------------------------
Standard errors in parentheses
Simulation code is below:
version 16.1
clear *
set seed 683728
* create scalar to be multplied by rnormal() when creating random intercept
scalar sd_sch_id = .5 // ICC = .5/4+.5 = .11
*scalar sd_residual = 4
* Schools
set obs 50
gen schid = _n
gen re_sch_id = sd_sch_id*rnormal() // random intercept, school level
* Students
expand 20
by schid, sort: gen stuid = _n
* create a vector that contains the equivalent of a lower triangular correlation matrix for x1, x2, and y
matrix c = (1, 0.5968, 1, 0.6623, 0.6174, 1)
* create a vector that contains the means of the variables
matrix m = (3.23,2.775,15.645)
* create a vector that contains the standard deviations
matrix sd = (1.05,1.47,4)
* draw a sample of 1000 cases from a normal distribution with specified correlation structure and specified means and standard deviations
drawnorm x1 x2 y, n(1000) corr(c) cstorage(lower) means(m) sds(sd)
corr y x1 x2 // looks good
*gen residual = sd_res*rnormal() // not needed b/c resiudal baked into drawnorm
* Add random effects to x1, x2, and y
egen pick1sch = tag(schid)
*x1 and x2
scalar sd_x1_sch = 1.2
scalar sd_x2_sch = .01
foreach v of varlist x1 x2 {
gen re_`v'_sch = sd_`v'_sch*rnormal() if pick1sch==1
bysort schid: replace re_`v'_sch = re_`v'_sch[_n-1] if missing(re_`v'_sch)
replace `v' = `v' + re_`v'_sch
}
*y
replace y = y + re_sch_id
foreach v of varlist x1 x2 y {
bysort schid: egen sch_mn_`v' = mean(`v')
gen cws_`v' = `v' - sch_mn_`v'
}
mixed y || schid: , stddev // sd = 0.76
eststo empty
mixed y x2 || schid:, stddev // sd = 0.76
eststo x2
mixed y x1 || schid:, stddev // sd = 3.30
eststo x1
mixed y x1 sch_mn_x1 || schid:, stddev // sd = 0.96
mixed y x1 x2 || schid:, stddev // sd = 2.04
eststo x1_x2