Exercise 2: Read and replicate the results in Chapter 5 of Cheng, C.-P., & Sheu, C.-F. (2015). Behavioral data analysis with R (Chinese). Yeh Yeh Book Gallery.
# 載入 mlmRev 套件
library(mlmRev)
# 載進資料
data(Chem97)
# 檢視套件提供的資訊
?Chem97
# 看資料結構
str(Chem97)'data.frame': 31022 obs. of 8 variables:
$ lea : Factor w/ 131 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
$ school : Factor w/ 2410 levels "1","2","3","4",..: 1 1 1 1 1 1 1 1 1 1 ...
$ student : Factor w/ 31022 levels "1","2","3","4",..: 1 2 3 4 5 6 7 8 9 10 ...
$ score : num 4 10 10 10 8 10 6 8 4 10 ...
$ gender : Factor w/ 2 levels "M","F": 2 2 2 2 2 2 2 2 2 2 ...
$ age : num 3 -3 -4 -2 -1 4 1 4 3 0 ...
$ gcsescore: num 6.62 7.62 7.25 7.5 6.44 ...
$ gcsecnt : num 0.339 1.339 0.964 1.214 0.158 ...
# 顯示前六筆資料
head(Chem97) lea school student score gender age gcsescore gcsecnt
1 1 1 1 4 F 3 6.625 0.339316
2 1 1 2 10 F -3 7.625 1.339316
3 1 1 3 10 F -4 7.250 0.964316
4 1 1 4 10 F -2 7.500 1.214316
5 1 1 5 8 F -1 6.444 0.158316
6 1 1 6 10 F 4 7.750 1.464316
# 去掉第六與第八個變項,並將變數重新命名
dta <- Chem97[, -c(6, 8)]
names(dta) <- c("區域", "學校", "學生", "化學", "性別", "總成績")
head(dta) 區域 學校 學生 化學 性別 總成績
1 1 1 1 4 F 6.625
2 1 1 2 10 F 7.625
3 1 1 3 10 F 7.250
4 1 1 4 10 F 7.500
5 1 1 5 8 F 6.444
6 1 1 6 10 F 7.750
# 顯示化學與總成績的描述性統計
sapply(dta[, c('化學', '總成績')], summary) 化學 總成績
Min. 0.00000 0.00000
1st Qu. 4.00000 5.75000
Median 6.00000 6.37500
Mean 5.81258 6.28568
3rd Qu. 8.00000 6.90000
Max. 10.00000 8.00000
sapply(dta[, c('化學', '總成績')], sd) 化學 總成績
3.319167 0.873451
# 計算各校化學和總成績平均分數及女性比率
dta_m <- aggregate(cbind(化學, 總成績, as.numeric(性別) - 1) ~ 學校,
data = dta, mean)
names(dta_m) <- c('學校', '化學平均', '總成績平均', '女性比率')
head(dta_m) 學校 化學平均 總成績平均 女性比率
1 1 8.30769 7.22446 1.000000
2 2 8.71429 7.02389 0.000000
3 3 4.66667 5.31000 0.666667
4 4 8.28571 6.23214 0.142857
5 5 5.50000 6.17431 0.437500
6 6 4.71429 6.70500 0.785714
# 載入 lattice ,準備畫圖
library(lattice)
# 以總成績與化學原始分數,繪製直方圖
p1 <- histogram(~ 總成績, data = dta, type = 'density',
xlab = '總成績', ylab = '機率密度')
p2 <- histogram(~ 化學, data = dta, type = 'density',
xlab = '化學分數', ylab = '機率密度')
# 以學校平均分數,繪製直方圖
p3 <- histogram(~ 總成績平均, data = dta_m, type = 'density',
xlab = '各校總成績平均', ylab = '機率密度')
p4 <- histogram(~ 化學平均, data = dta_m, type = 'density',
xlab = '各校化學平均分數', ylab = '機率密度')
# 計算學校標準差,存檔留後用
dta_sd <- aggregate(cbind(化學, 總成績) ~ 學校, data = dta, sd)
names(dta_sd)[2:3] <- c('化學標準差', '總成績標準差')
# 以學校標準差,繪製直方圖。
p5 <- histogram(~ 總成績標準差, data = dta_sd, type = 'density',
xlab = '各校總成績標準差', ylab = '機率密度')
p6 <- histogram(~ 化學標準差, data = dta_sd, type = 'density',
xlab = '各校化學分數標準差', ylab = '機率密度')# 載入 gridExtra ,把六張直方圖放一起
library(gridExtra)
grid.arrange(p6, p5, p4, p3, p2, p1, as.table = T)# 以學生層次計算化學與總成績相關係數為 .662
cor(dta[, c('化學', '總成績')]) 化學 總成績
化學 1.000000 0.662248
總成績 0.662248 1.000000
# 以學校層次計算化學與總成績生態相關(ecological correlation)係數為 .698
cor(dta_m[, -1]) 化學平均 總成績平均 女性比率
化學平均 1.000000 0.698065 0.066255
總成績平均 0.698065 1.000000 0.245209
女性比率 0.066255 0.245209 1.000000
plot(dta[, 4], dta[, 6], type = 'n', xlab ='化學分數', ylab = '總成績',
asp = 1)
grid()
# 學生
points(dta[, 4], dta[, 6], pch = '.', cex = 2)
abline(lm(dta[,6] ~ dta[, 4]))
# 學校
points(dta_m[, 2], dta_m[, 3], cex = 0.5, col = 'grey')
abline(lm(dta_m[,3] ~ dta_m[,2]), col = 'grey')
# 對角線
abline(0, 1, lty = 3, col = 'blue')# 載入 ggplot2 套件,準備畫圖。
library(ggplot2)
# 記錄下原始配色
old <- theme_set(theme_bw())
# 各校以化學預測總分時的截距與斜率
ggplot(data = dta, aes(x = 化學, y = 總成績, group = 學校))+
stat_smooth(method = 'lm', formula = y ~ x, se = F, color = 'lightgray') +
geom_point(size = 1) +
stat_smooth(aes(group = 1), method= 'lm', se = F, color = 'black') +
labs(x = '化學分數', y = '總成績', title = '學校')# 各區域以化學預測總分時的截距與斜率
ggplot(data = dta, aes(x = 化學, y = 總成績, group = 區域))+
stat_smooth(method = 'lm', formula = y ~ x, se = F, color = 'lightgray') +
geom_point(size = 1) +
stat_smooth(aes(group = 1), method = 'lm', se = F, color = 'black') +
labs(x = '化學分數', y = '總成績' , title = '區域') # 將變項以總分均置中,亦即,減去總平均。
dta$化學置中 <- scale(dta$化學, scale = F)
# 隨機選取25個學校與區域
set.seed(1225)
ns25 <- sample(levels(dta$學校), 25)
set.seed(1225)
nr25 <- sample(levels(dta$區域), 25)
# 重看一次各校以化學預測總分時的截距與斜率
ggplot(data = dta[dta$學校 %in% ns25, ], aes(x = 化學置中, y = 總成績, color = 性別))+
geom_point(size = 1) +
stat_smooth(method = 'lm', formula = y ~ x, se = F) +
facet_wrap( ~ 學校 )# 重看一次各區域以化學預測總分時的截距與斜率
ggplot(data = dta[dta$區域 %in% nr25, ], aes(x = 化學置中, y = 總成績, color = 性別))+
geom_point(size = 1) +
stat_smooth(method = 'lm', formula = y ~ x, se = F) +
facet_wrap( ~ 區域 )# 載入 lme4 套件,用來分析多層次資料
library(lme4)
# 將變項以總分均置中,亦即,減去總平均。
dta$化學置中 <- scale(dta$化學, scale = F)summary(m0 <- lmer(總成績 ~ 化學置中 + 性別 + 化學置中:性別 +
( 1 | 學校 ) + ( 1 | 區域 ), data = dta ) ) Linear mixed model fit by REML ['lmerMod']
Formula: 總成績 ~ 化學置中 + 性別 + 化學置中:性別 + (1 |
學校) + (1 | 區域)
Data: dta
REML criterion at convergence: 55708.4
Scaled residuals:
Min 1Q Median 3Q Max
-9.231 -0.567 0.064 0.653 4.079
Random effects:
Groups Name Variance Std.Dev.
學校 (Intercept) 0.0876 0.296
區域 (Intercept) 0.0106 0.103
Residual 0.3181 0.564
Number of obs: 31022, groups: 學校, 2410; 區域, 131
Fixed effects:
Estimate Std. Error t value
(Intercept) 6.08025 0.01326 458.43
化學置中 0.16808 0.00141 119.33
性別F 0.33409 0.00752 44.44
化學置中:性別F -0.01227 0.00209 -5.87
Correlation of Fixed Effects:
(Intr) 化學置中 性別F
化學置中 0.051
性別F -0.265 -0.065
化學置中:性別F -0.023 -0.630 0.067
# 試著去除區域的隨機效果,並看看去除隨機效果是否顯著。
m1 <- update(m0, . ~ . - ( 1 | 區域 ) )
anova(m0, m1)Data: dta
Models:
m1: 總成績 ~ 化學置中 + 性別 + (1 | 學校) + 化學置中:性別
m0: 總成績 ~ 化學置中 + 性別 + 化學置中:性別 + (1 | 學校) + (1 | 區域)
npar AIC BIC logLik deviance Chisq Df Pr(>Chisq)
m1 6 55743 55793 -27866 55731
m0 7 55685 55744 -27836 55671 59.74 1 1.08e-14
drop1(m0, test = 'Chisq')Single term deletions
Model:
總成績 ~ 化學置中 + 性別 + 化學置中:性別 + (1 |
學校) + (1 | 區域)
npar AIC LRT Pr(Chi)
<none> 55685
化學置中:性別 1 55718 34.39 4.52e-09
# 載入 coefplot2 套件,繪製固定效果
library(coefplot2)
coefplot2(m0)# 抽取變異成分,計算學校與區域可以解釋部分(ICCs)
print(vc <- lme4::VarCorr(m0), comp = 'Variance' ) Groups Name Variance
學校 (Intercept) 0.08763
區域 (Intercept) 0.01064
Residual 0.31811
vc <- as.data.frame(vc)
vc[vc$grp=='學校', 'vcov']/ sum(vc$vcov)[1] 0.210468
vc[vc$grp=='區域', 'vcov']/ sum(vc$vcov)[1] 0.0255473
1 - (vc[vc$grp=='Residual', 'vcov']/ sum(vc$vcov))[1] 0.236015
# 學校與區域層次的隨機效果QQ圖,檢查隨機效果是否呈常態
qq_r21 <- qqmath(~ ranef(m0)$學校, type = c('p', 'g', 'r'), pch = '.',
xlab = '常態分位數', ylab = '學校隨機效果分位數')
qq_r22 <- qqmath(~ ranef(m0)$區域, type = c('p', 'g', 'r'), pch = '.',
xlab = '常態分位數', ylab = '區域隨機效果分位數')
# 殘差的QQ圖,檢驗殘差是否呈常態
qq_r0 <- qqmath(~ resid(m0, scale = T), type = c('p', 'g', 'r'), pch = '.',
xlab = '標準化常態分位數', ylab = '標準化殘差')
# 預測值對殘差圖
m0_f <- data.frame(yhat=fitted(m0), zres=resid(m0, scaled=TRUE))
r_m0 <- ggplot(data = m0_f, aes(x = yhat, y = zres)) +
geom_point(pch = '.') +
stat_smooth(method = 'gam', formula = y ~ s(x, bs='cs'),
se = FALSE) +
labs( x = '預測值', y = '標準化殘差')
# 把圖放在一起呈現
library(gridExtra)
grid.arrange(qq_r21, qq_r22, qq_r0, r_m0, nrow = 2, ncol = 2)# 顯示複雜的多層次模型,包括隨機斜率效果、學校層次的預測變項以及跨層次交互作用
# 先要將不同層次資料併在一起
dta <- merge(dta, dta_m, by="學校")
rslt <- lmer(總成績 ~ 化學置中 + 性別 + 化學置中:性別 +
女性比率 + 女性比率:性別+
(1+化學置中+性別|學校) + (1|區域), data=dta)
summary(rslt)Linear mixed model fit by REML ['lmerMod']
Formula:
總成績 ~ 化學置中 + 性別 + 化學置中:性別 + 女性比率 +
女性比率:性別 + (1 + 化學置中 + 性別 | 學校) +
(1 | 區域)
Data: dta
REML criterion at convergence: 55393
Scaled residuals:
Min 1Q Median 3Q Max
-9.350 -0.561 0.068 0.650 4.123
Random effects:
Groups Name Variance Std.Dev. Corr
學校 (Intercept) 0.098117 0.3132
化學置中 0.000548 0.0234 -0.56
性別F 0.018077 0.1345 -0.63 0.07
區域 (Intercept) 0.010627 0.1031
Residual 0.310392 0.5571
Number of obs: 31022, groups: 學校, 2410; 區域, 131
Fixed effects:
Estimate Std. Error t value
(Intercept) 6.14024 0.01925 318.94
化學置中 0.16986 0.00156 109.11
性別F 0.14632 0.02226 6.57
女性比率 -0.22286 0.04002 -5.57
化學置中:性別F -0.01110 0.00216 -5.15
性別F:女性比率 0.43083 0.04823 8.93
Correlation of Fixed Effects:
(Intr) 化學置中 性別F 女性比率 化中:性別F
化學置中 -0.095
性別F -0.482 -0.004
女性比率 -0.705 0.069 0.645
化學置中:性別F 0.066 -0.608 0.004 -0.101
性別F:女性比率 0.494 -0.026 -0.915 -0.797 0.030
optimizer (nloptwrap) convergence code: 0 (OK)
Model failed to converge with max|grad| = 0.00683933 (tol = 0.002, component 1)