## tl;dr > [[ICC を直感的に理解する]] の主張を、答えの分かっているデータを作って R で確かめます。 > > 1. ICC を 0.7 に決めて作ったデータから、相関・回帰係数・分散分析の 3 とおりで 0.7 を取り出す > 2. ICC を 0 から 1 まで振ると、回帰係数がその値に追随する > > 同じ内容の Stata 版は [[ICC を直感的に理解する(シミュレーション編、Stata版)]] にあります。乱数の種を固定しているので、コピペすれば同じ数字が出ます。 ## ICC 0.7 のデータを作り、3 とおりに取り出す ICC を 0.7 に決めて 100 人分を作り、相関・回帰係数・分散分析の 3 とおりで取り出します。同じ値が出ます。 ```r # 700_icc_kakunin.R ICC 0.7 のデータを作り、3 とおりに取り出す #----------------------------------------- ## 準備 #----------------------------------------- set.seed(398) n <- 100 #----------------------------------------- ## 全体の設定 # 平均、全体の SD、ICC を決める #----------------------------------------- heikin <- 60 sd_zentai <- 10 icc <- 0.7 icc_igai <- 1 - icc #----------------------------------------- ## データを作る # ICC は分散の比として定義されているので、 # SD に配分して使うときにはルートをとる必要がある #----------------------------------------- # 実力は人ごとに一度だけ作る。2 回の測定で共有する jitsuryoku <- heikin + rnorm(n, 0, sd_zentai*sqrt(icc)) # 運 (un) はテストのたびに作り直す un_1 <- rnorm(n, 0, sd_zentai*sqrt(icc_igai)) un_2 <- rnorm(n, 0, sd_zentai*sqrt(icc_igai)) test_1 <- jitsuryoku + un_1 test_2 <- jitsuryoku + un_2 #----------------------------------------- ## 解析 #----------------------------------------- round(sapply(data.frame(jitsuryoku, un_1, un_2, test_1, test_2), function(x) c(mean = mean(x), sd = sd(x), min = min(x), max = max(x))), 1) # ICC である 0.7 が相関として示される # ICC は同じ人を 2 回測った値の相関である(正確には、2 回を入れ替え可能として扱った相関) cor(test_1, test_2) # 回帰でも同じ値 (0.7) が出る # 係数が 1 を下回るので、平均あたりを境に、上の人は下がり下の人は上がる # これで「もとが高い人ほど下がる!」は間違い。効果も変化も入れていない fit <- lm(test_2 ~ test_1) summary(fit)$coefficients # 縮んだと言うなら、比べる相手は 0 ではなく 1 b <- coef(fit)[2] se <- summary(fit)$coefficients[2, 2] tval <- (b - 1) / se c(t = tval, p = 2*pt(-abs(tval), df.residual(fit))) # ICC を一元配置の平均平方から出す。ICC(1,1) にあたる id <- factor(rep(1:n, 2)) test <- c(test_1, test_2) ms <- summary(aov(test ~ id))[[1]][["Mean Sq"]] (ms[1] - ms[2]) / (ms[1] + ms[2]) # 測定は 2 回なので k = 2 #----------------------------------------- ## 変化量をベースラインに回帰しても、同じことをしている #----------------------------------------- # 係数は 0.70 - 1 になる。t 値は上の (b - 1)/se と完全に一致する henka <- test_2 - test_1 summary(lm(henka ~ test_1))$coefficients ``` ``` jitsuryoku un_1 un_2 test_1 test_2 mean 59.5 0.7 0.3 60.2 59.8 sd 8.6 5.1 5.0 9.5 9.6 min 42.5 -11.5 -14.9 41.6 41.2 max 80.0 12.9 12.3 81.7 80.8 > cor(test_1, test_2) [1] 0.6972493 > summary(fit)$coefficients Estimate Std. Error t value Pr(>|t|) (Intercept) 17.5925074 4.43677951 3.965153 1.395321e-04 test_1 0.7014747 0.07284946 9.629099 7.727968e-16 > c(t = tval, p = 2*pt(-abs(tval), df.residual(fit))) t.test_1 p.test_1 -4.097838e+00 8.600319e-05 > (ms[1] - ms[2]) / (ms[1] + ms[2]) [1] 0.6991731 > summary(lm(henka ~ test_1))$coefficients Estimate Std. Error t value Pr(>|t|) (Intercept) 17.5925074 4.43677951 3.965153 1.395321e-04 test_1 -0.2985253 0.07284946 -4.097838 8.600319e-05 ``` 3 とおりの求め方が 0.70 の近くに揃います。 | 求め方 | 値 | |---|---| | `cor(test_1, test_2)` | 0.6972 | | `lm(test_2 ~ test_1)` の係数 | 0.7015 | | 平均平方から計算した ICC | 0.6992 | 設定した 0.70 に対して三桁目が揺れるのは、n = 100 だからです。種を引き直せば ±0.1 ほど動きます。回帰係数が相関とほぼ同じ値になるのは、`test_1` と `test_2` の SD が 9.5 と 9.6 でほぼ揃っているためです。 R には Stata の `icc` にあたる標準の関数がないので、一元配置の平均平方から直接計算しました。この値は Stata の `icc`(one-way)と一致します。同じデータを両方に渡して 0.6991731 と 0.6991732 になることを確認しています。`psych` パッケージを入れているなら `psych::ICC()` の `ICC1` が同じものです。 ### 落とし穴 係数が 1 を下回るので、上の人は下がり下の人は上がります。境目は 58.93 点です。 | test_1 | 予測 test_2 | 差 | |---|---|---| | 40 点 | 45.65 点 | +5.65 | | 58.93 点 | 58.93 点 | 0.00 | | 80 点 | 73.71 点 | −6.29 | **このデータには治療も変化も入っていません。**同じ人を 2 回測っただけで、こうなります。境目が平均の 60.2 点より少し低いのは標本のぶれで、`test_2` の平均が `test_1` より 0.4 点低く出たためです。母集団では境目が平均に一致します。全体を底上げする効果がないからです。 ただし、回帰表の $p < 0.001$ を根拠にはできません。あれは「係数がゼロでない」の検定で、1 回目が 2 回目をいくらかでも予測すれば通ります。縮んだと言いたいなら比べる相手は 1 で、$(b - 1)/\mathrm{se}$ を計算します。 そしてその検定は、変化量をベースラインに回帰したときの検定と完全に一致します。どちらも $t = -4.0978$、$p = 8.6 \times 10^{-5}$ です。変化量の回帰は別の解析に見えて、$\beta - 1$ を計算しているだけだからです。測定誤差があれば $\beta$ は必ず 1 を下回るので、この検定は何も起きていなくても通ります。詳しくは [[平均への回帰と回帰希釈を直感的に理解する]] を参照してください。 ## ICC を 6 条件で振ってみる 点数全体の SD を 10 に固定したまま、実力と運への配分だけを変えます。回帰係数が設定した ICC に追随します。 ```r library(ggplot2); library(dplyr); library(tidyr) set.seed(251) n <- 100 sd_total <- 10 # 点数全体の SD。どの条件でもこれに固定する mean_score <- 50 # 点数の平均 ICCs <- c(1.0, 0.9, 0.8, 0.6, 0.3, 0.0) # 点数の SD を 10 に固定し、実力と運に配分する tsukuru <- function(icc) { sd_jitsuryoku <- sd_total*sqrt(icc) # 実力の個人差 sd_un <- sd_total*sqrt(1 - icc) # 測るたびに変わる分(運) jitsuryoku <- rnorm(n, mean_score, sd_jitsuryoku) data.frame(id = 1:n, icc = icc, kai1 = jitsuryoku + rnorm(n, 0, sd_un), # 1 回目 kai2 = jitsuryoku + rnorm(n, 0, sd_un)) # 2 回目 } d <- bind_rows(lapply(ICCs, tsukuru)) # 回帰係数と相関を出す d %>% group_by(icc) %>% summarise(回帰係数 = coef(lm(kai2 ~ kai1))[2], 相関 = cor(kai1, kai2)) ``` ``` icc 回帰係数 相関 1 0.0 -0.026 -0.026 2 0.3 0.286 0.297 3 0.6 0.595 0.644 4 0.8 0.802 0.702 5 0.9 0.890 0.942 6 1.0 1.000 1.000 ``` 回帰係数と相関は、原理的には同じ値になります。一致しないのは、1 回目と 2 回目の SD が標本では微妙に違ってくるためです。人数を増やせば一致します。 ## 次に読む - [[ICC を直感的に理解する]] — この記事が確かめている理屈 - [[ICC を直感的に理解する(シミュレーション編、Stata版)]] — 同じ内容の Stata 版 - [[平均への回帰と回帰希釈を直感的に理解する]] — 「ベースラインが悪い人ほど改善が大きい」が測定誤差だけで出てしまう話 - [[R - ICC を計算してみよう(評価者間一致研究)]] — 実データから ICC を計算する手順