library(tidyverse)
library(car) # VIF の計算重回帰分析
複数の説明変数を用いる重回帰分析について学びます。
パッケージの読み込み
データの準備
単回帰分析で用いた学習時間とテスト得点の例に,睡眠時間と模試の事前得点を説明変数として追加する(n = 80)。
set.seed(123)
n <- 80
df <- tibble(
study_hours = runif(n, min = 0, max = 8),
sleep_hours = runif(n, min = 4, max = 9),
prior_score = rnorm(n, mean = 55, sd = 10),
noise = rnorm(n, mean = 0, sd = 6)
) |>
mutate(
test_score = 20 + 5 * study_hours + 2 * sleep_hours +
0.4 * prior_score + noise,
test_score = pmin(test_score, 100)
) |>
select(-noise)
summary(df) study_hours sleep_hours prior_score test_score
Min. :0.004998 Min. :4.052 Min. :34.47 Min. : 44.02
1st Qu.:2.088011 1st Qu.:5.212 1st Qu.:48.56 1st Qu.: 63.63
Median :3.765116 Median :6.279 Median :54.05 Median : 75.84
Mean :4.011478 Mean :6.465 Mean :54.51 Mean : 74.64
3rd Qu.:6.043770 3rd Qu.:7.617 3rd Qu.:60.74 3rd Qu.: 84.99
Max. :7.954158 Max. :8.925 Max. :76.87 Max. :100.00
単回帰から重回帰へ
モデル
説明変数が 1 つの単回帰モデルを拡張し,\(k\) 個の説明変数 \(x_1, \dots, x_k\) で目的変数 \(y\) を説明する。
\[ y_i = \beta_0 + \beta_1 x_{1i} + \beta_2 x_{2i} + \cdots + \beta_k x_{ki} + \varepsilon_i, \quad \varepsilon_i \sim N(0, \sigma^2) \]
\(\beta_j\) は「他の説明変数を一定に保ったときの,\(x_j\) が 1 単位増えることによる \(y\) の変化量」を表す偏回帰係数である。
最小二乗法(OLS)
単回帰と同様に,残差二乗和を最小にする係数を求める。
\[ \hat{\boldsymbol{\beta}} = \arg\min_{\boldsymbol{\beta}} \sum_{i=1}^{n} \varepsilon_i^2 = \arg\min_{\boldsymbol{\beta}} \sum_{i=1}^{n} \left( y_i - \beta_0 - \sum_{j=1}^{k} \beta_j x_{ji} \right)^2 \]
行列表記では,計画行列 \(X\)(1 列目は切片用の 1)を用いて次の閉じた解が得られる。
\[ \hat{\boldsymbol{\beta}} = (X^\top X)^{-1} X^\top \mathbf{y} \]
説明変数間に強い相関がある(多重共線性が高い)場合,\(X^\top X\) がほぼ特異となり係数の推定が不安定になる点に注意する。
lm() による推定
model <- lm(test_score ~ study_hours + sleep_hours + prior_score, data = df)
summary(model)
Call:
lm(formula = test_score ~ study_hours + sleep_hours + prior_score,
data = df)
Residuals:
Min 1Q Median 3Q Max
-8.140 -4.047 -0.688 3.178 13.537
Coefficients:
Estimate Std. Error t value Pr(>|t|)
(Intercept) 18.8086 4.3744 4.300 5.02e-05 ***
study_hours 4.8953 0.2628 18.626 < 2e-16 ***
sleep_hours 1.7347 0.4246 4.085 0.000108 ***
prior_score 0.4582 0.0628 7.296 2.42e-10 ***
---
Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
Residual standard error: 5.277 on 76 degrees of freedom
Multiple R-squared: 0.8543, Adjusted R-squared: 0.8486
F-statistic: 148.6 on 3 and 76 DF, p-value: < 2.2e-16
出力の読み方
| 項目 | Estimate | Std. Error | t value | Pr(>|t|) |
|---|---|---|---|---|
| 切片 β̂₀ | 18.8086 | 4.3744 | 4.2997 | 1e-04 |
| 学習時間 β̂₁ | 4.8953 | 0.2628 | 18.6260 | 0e+00 |
| 睡眠時間 β̂₂ | 1.7347 | 0.4246 | 4.0852 | 1e-04 |
| 事前得点 β̂₃ | 0.4582 | 0.0628 | 7.2963 | 0e+00 |
単回帰の出力との違いは,各説明変数の係数が「他の変数を一定に保ったときの」効果として推定される点である。
自由度調整済み決定係数
説明変数を増やすと \(R^2\) は単調に増加してしまうため,変数の数で罰則をかけた自由度調整済み決定係数で当てはまりを比較する。
\[ R^2_{\text{adj}} = 1 - (1 - R^2) \frac{n - 1}{n - k - 1} \]
r2 <- summary(model)$r.squared
r2_adj <- summary(model)$adj.r.squared
cat(sprintf("R² = %.3f\n", r2))R² = 0.854
cat(sprintf("調整済み R² = %.3f\n", r2_adj))調整済み R² = 0.849
多重共線性の確認(VIF)
説明変数間の相関が強いと係数の標準誤差が膨らみ,推定が不安定になる。VIF(分散拡大係数)で確認する。
\[ \text{VIF}_j = \frac{1}{1 - R_j^2} \]
ここで \(R_j^2\) は,\(x_j\) を他のすべての説明変数で回帰したときの決定係数である。
vif(model)study_hours sleep_hours prior_score
1.026433 1.027571 1.003329
| VIF の目安 | 解釈 |
|---|---|
| < 5 | 問題なし |
| 5〜10 | やや注意 |
| > 10 | 多重共線性が強く疑われる |
モデル比較とモデル選択
説明変数の組み合わせを変えたモデルを AIC(赤池情報量規準) で比較する。値が小さいほど良いモデルとされる。
model_simple <- lm(test_score ~ study_hours, data = df)
model_full <- lm(test_score ~ study_hours + sleep_hours + prior_score, data = df)
tibble(
モデル = c("単回帰(study_hours のみ)", "重回帰(全変数)"),
AIC = c(AIC(model_simple), AIC(model_full)),
`調整済みR²` = c(summary(model_simple)$adj.r.squared,
summary(model_full)$adj.r.squared)
) |>
knitr::kable(digits = 3)| モデル | AIC | 調整済みR² |
|---|---|---|
| 単回帰(study_hours のみ) | 548.958 | 0.711 |
| 重回帰(全変数) | 499.069 | 0.849 |
step() を使うと,AIC を基準に変数増減法で自動的にモデルを選択できる。
model_step <- step(model_full, direction = "both")
formula(model_step)予測
new_data <- tibble(
study_hours = c(2, 4, 6),
sleep_hours = c(6, 7, 7.5),
prior_score = c(50, 55, 60)
)
predict(model, newdata = new_data, interval = "confidence") fit lwr upr
1 61.91856 60.22936 63.60777
2 75.73503 74.47514 76.99493
3 88.68413 86.83826 90.53000
predict(model, newdata = new_data, interval = "confidence") |>
round(2) |>
cbind(new_data) |>
select(study_hours, sleep_hours, prior_score, fit, lwr, upr) |>
knitr::kable(col.names = c("学習時間", "睡眠時間", "事前得点",
"予測得点", "下限 (95%)", "上限 (95%)"))| 学習時間 | 睡眠時間 | 事前得点 | 予測得点 | 下限 (95%) | 上限 (95%) |
|---|---|---|---|---|---|
| 2 | 6.0 | 50 | 61.92 | 60.23 | 63.61 |
| 4 | 7.0 | 55 | 75.74 | 74.48 | 76.99 |
| 6 | 7.5 | 60 | 88.68 | 86.84 | 90.53 |
まとめ
| 関数 | 役割 |
|---|---|
| lm(y ~ x1 + x2 + …, data) | 重回帰モデルの OLS 推定 |
| summary(model) | 偏回帰係数・R²・F 統計量の出力 |
| summary(model)$adj.r.squared | 自由度調整済み決定係数の取得 |
| vif(model) | 多重共線性(VIF)の確認 |
| AIC(model) | モデルの AIC の計算 |
| step(model, direction = ‘both’) | AIC によるステップワイズ変数選択 |
| predict(model, newdata, interval = ‘confidence’) | 予測値と信頼区間の計算 |
単回帰と同様に,重回帰でも残差診断(plot(model))で線形性・等分散性・正規性・独立性を確認することが望ましい。