回帰分析: 変数$X$で変数$Y$を説明する
$X$ が $Y$ に影響していると想定
例:
線形回帰(直線回帰): 関係性が線形(直線で表せる)
データセット ($X_i$, $Y_i$) ($i=1, \cdots, n$)について,回帰直線を求める. 直線は,
$$y = a + bx$$の形で表せるので,切片$a$と傾き$b$を求めたい.
説明変数 $X_i$に対して回帰直線上の$Y$を$\hat{Y}_i$とすると,次のようになる.
$$\hat{Y}_i = a + b X_i$$回帰直線上の$\hat{Y}_i$と実際のデータ$Y_i$ との残差を $\epsilon_i = Y_i - \hat{Y}_i$ とする.
この残差の和が最小になるような,切片$a$と傾き$b$を求める.
実際には,二乗した和(残差平方和)を最小にすることを考える.
$$\sum\limits^n_{i=1}\epsilon_i^2 = \sum\limits^n_{i=1} (Y_i - \hat{Y}_i)^2$$最も当てはまりのよい直線を求める
パッケージ読み込み
library(dplyr)
library(ggplot2)
図9.2 (a)年齢と血圧の関係
d1 <- data.frame(
age = c(19, 23, 27, 35, 44, 51, 59, 66),
blood_pressure = c(124, 117, 120, 132, 128, 142, 143, 135)
)
options(repr.plot.width = 4, repr.plot.height=4)
ggplot(d1, aes(age, blood_pressure)) + geom_point() +
scale_x_continuous(limits = c(10, 70)) + scale_y_continuous(limits=c(110, 150))
正規方程式で $a$ と $b$ を求める
b.d1 <- d1 %>%
mutate(x = age - mean(age), y = blood_pressure - mean(blood_pressure)) %>%
mutate(xy = x * y) %>%
summarise(SP.xy = sum(xy), SS.x = sum(x**2)) %>%
summarise(b = SP.xy / SS.x) %>% .[["b"]]
a.d1 <- with(mean(blood_pressure) - b.d1 * mean(age), data=d1)
ggplot(d1, aes(age, blood_pressure)) + geom_point() +
scale_x_continuous(limits = c(10, 70)) + scale_y_continuous(limits=c(110, 150)) +
geom_abline(slope = b.d1, intercept = a.d1) +
annotate("text", x=10, y = 150, hjust=0, vjust=0, label=sprintf("a = %.2f", a.d1)) +
annotate("text", x=10, y = 147, hjust=0, vjust=0, label=sprintf("b = %.4f", b.d1))
回帰直線が有意かどうか
図9.2(b) 年齢と血圧の関係
(a)と切片と傾きは似ているが,直線からの乖離が大きい
d2 <- data.frame(
age = c(19, 23, 27, 35, 44, 51, 59, 66),
blood_pressure = c(111, 129, 113, 137, 147, 126, 135, 139)
)
b.d2 <- d2 %>%
mutate(x = age - mean(age), y = blood_pressure - mean(blood_pressure)) %>%
mutate(xy = x * y) %>%
summarise(SP.xy = sum(xy), SS.x = sum(x**2)) %>%
summarise(b = SP.xy / SS.x) %>% .[["b"]]
a.d2 <- with(mean(blood_pressure) - b.d2 * mean(age), data=d2)
ggplot(d2, aes(age, blood_pressure)) + geom_point() +
scale_x_continuous(limits = c(10, 70)) + scale_y_continuous(limits=c(110, 150)) +
geom_abline(slope = b.d2, intercept = a.d2) +
annotate("text", x=10, y = 150, hjust=0, vjust=0, label=sprintf("a = %.2f", a.d2)) +
annotate("text", x=10, y = 147, hjust=0, vjust=0, label=sprintf("b = %.4f", b.d2))
図 9.2(c) (b) と同じデータをつなげたもの(サンプル数が2倍)
d3 <- bind_rows(d2, d2)
b.d3 <- d3 %>%
mutate(x = age - mean(age), y = blood_pressure - mean(blood_pressure)) %>%
mutate(xy = x * y) %>%
summarise(SP.xy = sum(xy), SS.x = sum(x**2)) %>%
summarise(b = SP.xy / SS.x) %>% .[["b"]]
a.d3 <- with(mean(blood_pressure) - b.d3 * mean(age), data=d3)
ggplot(d3, aes(age, blood_pressure)) + geom_point() +
scale_x_continuous(limits = c(10, 70)) + scale_y_continuous(limits=c(110, 150)) +
geom_abline(slope = b.d3, intercept = a.d3) +
annotate("text", x=10, y = 150, hjust=0, vjust=0, label=sprintf("a = %.2f", a.d3)) +
annotate("text", x=10, y = 147, hjust=0, vjust=0, label=sprintf("b = %.4f", b.d3))
Rで線形回帰をするには,lm()
関数を使う
(a)だと,
lm(blood_pressure ~ age, data = d1) %>% summary()
(b)
lm(blood_pressure ~ age, data = d2) %>% summary()
(c)
lm(blood_pressure ~ age, data = d3) %>% summary()
有意性を強める要因
回帰直線の適合度: 標準誤差(Residual standard error)
残差平方和
$$ \sum\limits^n_{i=1}(Y_i - \hat{Y}_i)^2 = \sum\limits^n_{i=1}[Y_i - (bX_i + a)]^2 $$回帰の残差分散 $s^2$: 残差平方和 / 自由度.自由度は サンプル数 - パラメータ数(a, b) = n - 2
$$ s^2 = \frac{1}{n-2}\sum\limits^n_{i=1}[Y_i - (bX_i + a)]^2 $$回帰の標準誤差 $s$: 残差平方和の平方根
$$ s = \sqrt{\frac{1}{n-2}\sum\limits^n_{i=1}[Y_i - (bX_i + a)]^2} $$(a)だと,
d1 %>%
mutate(y_hat = age * b.d1 + a.d1) %>%
summarise(s = sqrt(sum((blood_pressure - y_hat)**2) / (n() - 2)))
直線回帰の有意性検定
母集団における真の傾きを $\beta$ とすると,
図9.3 両方とも有意ではない
以下の統計量 $t$ が自由度$n-2$の$t$分布に従う
$$ t = \frac{(b - \beta)\sqrt{\sum\limits^n_{i=1}(X_i - \bar{X}_i)^2}}{s_\mathrm{e}} $$ここで,$s_\mathrm{e}$ は回帰の標準誤差
a だと,
# t
d1 %>% summarise(t = b.d1 * sqrt(sum((age - mean(age))**2)) / 5.83)
# p値
1 - pt(q = 3.62, df = 4)
実際のデータ点の平均値からの乖離
$$ \sum\limits^n_{i=1}(Y_i - \bar{Y}_i)^2 $$# total SS
(SS.total <- with(sum((blood_pressure - mean(blood_pressure))**2), data = d1))
回帰で得られた予測値の,実際の平均値からの乖離
$$ \sum\limits^n_{i=1}(\hat{Y}_i - \bar{Y}_i)^2 $$# regression SS
(SS.reg <- with(sum(((age * b.d1 + a.d1 - mean(blood_pressure)))**2), data = d1))
実際のデータ点と予測値との乖離
$$ \sum\limits^n_{i=1}(Y_i - \hat{Y}_i)^2 $$# residual SS
(SS.res <- with(sum((blood_pressure - (age * b.d1 + a.d1))**2), data=d1))
総平方和 = 回帰平方和 + 残差平方和
identical(all.equal(SS.total, SS.reg + SS.res), TRUE)
# degree of freedom
## total
df.total <- nrow(d1) - 1
## regression
df.reg <- 1
## residual
df.res <- nrow(d1) - 2
# F value
(f_val <- (SS.reg / df.reg) / (SS.res / df.res))
# p value
1 - pf(q = 13.12, df1 = 1, df2 = 6)
説明変数$X$ が応答変数$Y$をどれだけ説明しているかを表す.寄与率とも言う.
$$ r^2 \equiv 1 - \frac{\sum\limits^n_{i = 1}(Y_i - \hat{Y}_i)^2}{\sum\limits^n_{i = 1}(Y_i - \bar{Y}_i)^2} $$つまり,
$$r^2 \equiv 1 - \frac{\text{残差平方和}}{\text{総平方和}} = \frac{回帰平方和}{総平方和}$$さっきのF値は,
$$ F = \frac{回帰平方和 / 1}{残差平方和 / n-2} = \frac{r^2}{(1-r^2) / (n-2)}$$決定係数を求めると,
# Multiple R-squared
1 - (SS.res / SS.total)
Adjusted R-squared は,自由度調整済み決定係数
# Adjusted R-squared
1 - (SS.res / df.res) / (SS.total / df.total)
(1)親の結婚年数と子の結婚年数
d4 <- data.frame(
x = c(1,2,4,5,3,2,3,1,5,4,4,2),
y = c(3,4,4,5,5,3,4,3,6,6,5,5)
)
gp.d4 <- ggplot(d4, aes(x, y)) + geom_point() + xlim(0, 7) + ylim(0, 7) + xlab("Parent (year)") + ylab("Children (year)")
gp.d4
res.d4 <- lm(y ~ x, data=d4)
res.d4 %>% summary()
gp.d4 + geom_abline(slope = coef(res.d4)[["x"]], intercept = coef(res.d4)[["(Intercept)"]])
(2)雀の雛の成長(日齢と羽根の長さ)
d5 <- data.frame(
x = c(3,4,5,6,8,9,10,11,12,14,15,16,17),
y = c(1.4, 1.5, 2.2, 2.4, 3.1, 3.2, 3.2, 3.9, 4.1, 4.7, 4.5, 5.2, 5)
)
gp.d5 <- ggplot(d5, aes(x, y)) + geom_point() + xlim(0, 20) + ylim(0, 6) + xlab("Year") + ylab("Wing size (cm)")
gp.d5
res.d5 <- lm(y ~ x, data=d5)
summary(res.d5)
gp.d5 + geom_abline(slope = coef(res.d5)[["x"]], intercept = coef(res.d5)[["(Intercept)"]])
求めた回帰直線にどれぐらいの誤差があるかを考える.
回帰直線 $y = ax + b$ について, $X^\ast$ における推定値 $\hat{Y}^\ast$ を計算したとき, 回帰式の $100 (1 - \alpha)$ % 信頼区間は,
$$ \hat{Y}^\ast \pm t_{(n-2, \alpha / 2)} s_e \sqrt{\frac{1}{n} + \frac{(X^\ast - \bar{X}^\ast)^2}{\sum^n_{i=1}(X_i - \bar{X})^2}} $$ここで,
predict(res.d5, interval="confidence")
d5.conf <- predict(res.d5, interval="confidence") %>% as.data.frame()
d5.conf
ggplot(bind_cols(d5, d5.conf)) +
geom_point(mapping =aes(x, y)) +
geom_line(mapping=aes(x, upr), linetype="dashed") +
geom_line(mapping=aes(x, fit)) +
geom_line(mapping=aes(x, lwr), linetype="dashed") +
xlim(0, 20) + ylim(0, 6) + xlab("Year") + ylab("Wing size (cm)")
回帰の95%予測区間: データプロットの95%が含まれる
$$ \hat{Y}^\ast \pm t_{(n-2, \alpha / 2)} s_e \sqrt{1 + \frac{1}{n} + \frac{(X^\ast - \bar{X})^2}{\sum^n_{i=1}(X_i - \bar{X})^2}}$$d5.pred <- predict(res.d5, interval="prediction") %>% as.data.frame()
d5.pred
ggplot(bind_cols(d5, d5.pred)) +
geom_point(mapping =aes(x, y)) +
geom_line(mapping=aes(x, upr), linetype="dashed") +
geom_line(mapping=aes(x, fit)) +
geom_line(mapping=aes(x, lwr), linetype="dashed") +
xlim(0, 20) + ylim(0, 6) + xlab("Year") + ylab("Wing size (cm)")
単回帰分析で扱えるデータは限られる
光化学スモッグ発生回数と正午に30℃を超えた日数の関係
d.ex <- data.frame(
nsmog = c(91, 70, 103, 79, 86, 114, 101, 82, 75, 87),
n30 = c(14, 5, 28, 17, 15, 19, 20, 7, 10, 9)
)
ggplot(d.ex, aes(n30, nsmog)) + geom_point() + xlim(0, 30) + ylim(50, 150)
res.ex <- lm(nsmog ~ n30, data=d.ex)
summary(res.ex)
d.ex.conf <- predict(res.ex, interval="confidence") %>% as.data.frame()
ggplot(bind_cols(d.ex, d.ex.conf)) +
geom_point(aes(n30, nsmog)) + xlim(0, 30) + ylim(50, 150) +
geom_line(aes(n30, upr), linetype="dashed") +
geom_line(aes(n30, fit)) +
geom_line(aes(n30, lwr), linetype="dashed")
devtools::session_info()