2年生では記述統計(ヒストグラム・代表値・散布度・箱ひげ図)を学んだ。 3年生ではそれを土台に、「グループ間の差は偶然か?」「2変数間に関係はあるか?」 という問いに統計的に答える手法を学ぶ。
記述統計(復習)
↓
質 × 量 の可視化:平行箱ひげ図(Private 別の Grad.Rate)
↓
量 × 量 の可視化:散布図(Outstate × Grad.Rate)
↓
t 検定:私立 vs 公立の卒業率に差があるか?(2群の平均値の比較)
↓
単回帰分析:授業料は卒業率を説明できるか?(量 × 量の関係を数式で)
↓
ANOVA(分散分析):回帰モデルは全体として意味があるか?
今回使う変数:
| 変数名 | 型 | 説明 |
|---|---|---|
Private |
質的(2値) | 私立か否か(Yes / No) |
Grad.Rate |
量的(連続) | 卒業率(%)← 目的変数 |
Outstate |
量的(連続) | 州外学生の授業料(ドル)← 説明変数 |
Expend |
量的(連続) | 学生一人当たり支出(ドル)← 説明変数(参考) |
# ---------------------------------------------------------------
# 使用パッケージ
# tidyverse : データ操作(dplyr)と可視化(ggplot2)をまとめて読み込む
# cowplot : 複数の ggplot2 グラフを並べて表示するパッケージ
# ---------------------------------------------------------------
library(tidyverse)
library(cowplot)# ---------------------------------------------------------------
# データの読み込み
# ---------------------------------------------------------------
college <- read.csv("ISLR_CSV_Data/College.csv")
# ---------------------------------------------------------------
# 【分析対象変数の短縮代入】
# 毎回 college$変数名 と書くのは冗長なので、
# よく使う変数をあらかじめ短い名前に代入しておく。
# y : 目的変数 = 卒業率(Grad.Rate)
# x : 説明変数 = 州外学生の授業料(Outstate)
# ---------------------------------------------------------------
y <- college$Grad.Rate # 目的変数:卒業率(%)
x <- college$Outstate # 説明変数:州外学生の授業料(ドル)
# 読み込み確認:先頭5行と変数の型を確認する
head(college, 5)## 'data.frame': 777 obs. of 19 variables:
## $ X : chr "Abilene Christian University" "Adelphi University" "Adrian College" "Agnes Scott College" ...
## $ Private : chr "Yes" "Yes" "Yes" "Yes" ...
## $ Apps : int 1660 2186 1428 417 193 587 353 1899 1038 582 ...
## $ Accept : int 1232 1924 1097 349 146 479 340 1720 839 498 ...
## $ Enroll : int 721 512 336 137 55 158 103 489 227 172 ...
## $ Top10perc : int 23 16 22 60 16 38 17 37 30 21 ...
## $ Top25perc : int 52 29 50 89 44 62 45 68 63 44 ...
## $ F.Undergrad: int 2885 2683 1036 510 249 678 416 1594 973 799 ...
## $ P.Undergrad: int 537 1227 99 63 869 41 230 32 306 78 ...
## $ Outstate : int 7440 12280 11250 12960 7560 13500 13290 13868 15595 10468 ...
## $ Room.Board : int 3300 6450 3750 5450 4120 3335 5720 4826 4400 3380 ...
## $ Books : int 450 750 400 450 800 500 500 450 300 660 ...
## $ Personal : int 2200 1500 1165 875 1500 675 1500 850 500 1800 ...
## $ PhD : int 70 29 53 92 76 67 90 89 79 40 ...
## $ Terminal : int 78 30 66 97 72 73 93 100 84 41 ...
## $ S.F.Ratio : num 18.1 12.2 12.9 7.7 11.9 9.4 11.5 13.7 11.3 11.5 ...
## $ perc.alumni: int 12 16 30 37 2 11 26 37 23 15 ...
## $ Expend : int 7041 10527 8735 19016 10922 9727 8861 11487 11644 8991 ...
## $ Grad.Rate : int 60 56 54 59 15 55 63 73 80 52 ...
# ---------------------------------------------------------------
# 【重要】質的変数をファクター型に変換する
#
# Rでは質的変数(カテゴリ変数)を「factor(因子)型」として
# 明示的に指定する必要がある。
# 指定しないと文字列(character)型のまま扱われ、
# t検定・ANOVA・グループ別集計が正しく動かない場合がある。
#
# as.factor() で変換し、levels() で水準(グループ)を確認できる。
# ---------------------------------------------------------------
college$Private <- as.factor(college$Private) # 文字列 → ファクター型へ変換
levels(college$Private) # 水準の確認:「No」「Yes」の2グループ## [1] "No" "Yes"
##
## No Yes
## 212 565
# ---------------------------------------------------------------
# 2年生の復習:目的変数 Grad.Rate の基本統計量をまとめて確認
# ---------------------------------------------------------------
summary(x)## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 2340 7320 9990 10441 12925 21700
# 主要な統計量を一覧表で表示
desc_table <- data.frame(
統計量 = c("データ数", "平均値", "中央値", "標準偏差",
"Q1(25%点)", "Q3(75%点)", "四分位範囲(IQR)",
"最小値", "最大値"),
値 = round(c(
length(y),
mean(y),
median(y),
sd(y),
quantile(y, 0.25),
quantile(y, 0.75),
IQR(y),
min(y),
max(y)
), 2)
)
knitr::kable(desc_table, caption = "卒業率(Grad.Rate)の記述統計量",
align = c("l","r"))| 統計量 | 値 |
|---|---|
| データ数 | 777.00 |
| 平均値 | 65.46 |
| 中央値 | 65.00 |
| 標準偏差 | 17.18 |
| Q1(25%点) | 53.00 |
| Q3(75%点) | 78.00 |
| 四分位範囲(IQR) | 25.00 |
| 最小値 | 10.00 |
| 最大値 | 118.00 |
# 2年生の復習:ヒストグラムと箱ひげ図を並べて表示
p1 <- ggplot(college, aes(x = Grad.Rate)) +
geom_histogram(binwidth = 5, fill = "steelblue", color = "white") +
geom_vline(xintercept = mean(y),
color = "red", linetype = "solid", linewidth = 1) +
geom_vline(xintercept = median(y),
color = "darkorange", linetype = "dashed", linewidth = 1) +
labs(title = "ヒストグラム", x = "卒業率(%)", y = "度数") +
theme_bw()
p2 <- ggplot(college, aes(x = Grad.Rate, y = "")) +
geom_boxplot(fill = "steelblue", outlier.color = "red", outlier.size = 2) +
labs(title = "箱ひげ図", x = "卒業率(%)", y = "") +
theme_bw()
plot_grid(p1, p2, ncol = 1, rel_heights = c(2, 1))# ---------------------------------------------------------------
# 【平行箱ひげ図とは?】
# 質的変数(グループ)ごとに量的変数の箱ひげ図を並べて描いたもの。
# グループ間の分布の違い(中央値・ばらつき・外れ値)を
# 一目で比較できる。
#
# ここでは「私立(Yes)」と「公立(No)」で
# 卒業率(Grad.Rate)の分布を比較する。
# ---------------------------------------------------------------
ggplot(college, aes(x = Private, y = Grad.Rate, fill = Private)) +
geom_boxplot(
color = "black",
outlier.color = "red",
outlier.size = 2,
width = 0.5
) +
# 実際のデータ点を半透明で重ねる(分布の形をより詳しく確認)
geom_jitter(
width = 0.15, alpha = 0.2, size = 1, color = "black"
) +
scale_fill_manual(
values = c("No" = "lightcoral", "Yes" = "steelblue"),
labels = c("No" = "公立", "Yes" = "私立")
) +
scale_x_discrete(labels = c("No" = "公立", "Yes" = "私立")) +
labs(
title = "私立・公立別の卒業率の分布",
subtitle = "箱ひげ図+データ点(赤点は外れ値)",
x = "大学の種別",
y = "卒業率(%)",
fill = "種別"
) +
theme_bw() +
theme(legend.position = "none") # 凡例は軸ラベルで十分なので非表示# ---------------------------------------------------------------
# グループ別の記述統計量を数値でも確認する
#
# dplyr の group_by() + summarise() の組み合わせで
# グループごとに任意の統計量を計算できる。
# group_by(Private) : Private の水準ごとにグループ化
# summarise() : グループごとに統計量を集計
# n() : グループのデータ件数
# ---------------------------------------------------------------
college %>%
group_by(Private) %>%
summarise(
件数 = n(),
平均値 = round(mean(Grad.Rate), 2),
中央値 = round(median(Grad.Rate), 2),
標準偏差 = round(sd(Grad.Rate), 2),
Q1 = round(quantile(Grad.Rate, 0.25), 2),
Q3 = round(quantile(Grad.Rate, 0.75), 2),
IQR = round(IQR(Grad.Rate), 2)
) %>%
knitr::kable(caption = "私立・公立別の卒業率の記述統計量")| Private | 件数 | 平均値 | 中央値 | 標準偏差 | Q1 | Q3 | IQR |
|---|---|---|---|---|---|---|---|
| No | 212 | 56.04 | 55 | 14.58 | 46 | 65 | 19 |
| Yes | 565 | 69.00 | 69 | 16.75 | 58 | 81 | 23 |
視覚的な確認ポイント: - 私立と公立で、卒業率の中央値(箱の中線)はどちらが高いか? - ばらつき(箱の高さ=IQR)はどちらが大きいか? - 外れ値(赤い点)はどちらのグループに多いか?
これらを次の t 検定で「統計的に有意な差か」確認する。
# ---------------------------------------------------------------
# 【散布図とは?】
# 2つの量的変数の関係を点でプロットしたグラフ。
# 横軸(x)に説明変数、縦軸(y)に目的変数を置くのが慣例。
#
# ここでは「授業料(Outstate)」が「卒業率(Grad.Rate)」と
# どのような関係にあるかを確認する。
#
# geom_smooth(method = "lm") : 線形回帰直線を重ねて描く
# method = "lm" → 線形モデル(Linear Model)による回帰直線
# se = TRUE → 95%信頼区間を帯状に表示(デフォルト TRUE)
# ---------------------------------------------------------------
ggplot(college, aes(x = x, y = y)) +
geom_point(
alpha = 0.4, # 点の透明度(重なりを見やすくする)
size = 1.5,
color = "steelblue"
) +
geom_smooth(
method = "lm", # 線形回帰直線を追加
color = "red",
linewidth = 1,
se = TRUE # 95%信頼区間を帯で表示
) +
labs(
title = "授業料と卒業率の関係",
subtitle = "赤線:線形回帰直線 帯:95%信頼区間",
x = "州外学生の授業料(ドル)",
y = "卒業率(%)"
) +
theme_bw()# ---------------------------------------------------------------
# 私立・公立を色分けして散布図を描く
# グループによって関係のパターンが異なるかも確認できる。
# ---------------------------------------------------------------
ggplot(college, aes(x = x, y = y, color = Private)) +
geom_point(alpha = 0.4, size = 1.5) +
geom_smooth(method = "lm", se = FALSE, linewidth = 1) +
scale_color_manual(
values = c("No" = "lightcoral", "Yes" = "steelblue"),
labels = c("No" = "公立", "Yes" = "私立")
) +
labs(
title = "授業料と卒業率の関係(私立・公立別)",
subtitle = "各グループに個別の回帰直線を重ねて表示",
x = "州外学生の授業料(ドル)",
y = "卒業率(%)",
color = "種別"
) +
theme_bw()# ---------------------------------------------------------------
# 【相関係数の確認】
# cor() で2変数間のピアソン積率相関係数を計算できる。
# +1 に近い → 強い正の相関(一方が増えると他方も増える)
# -1 に近い → 強い負の相関(一方が増えると他方は減る)
# 0 に近い → 相関なし
# 目安:|r| > 0.7 → 強い相関 |r| > 0.4 → 中程度 |r| < 0.2 → 弱い
# ---------------------------------------------------------------
cor(x, y) # 授業料と卒業率の相関係数## [1] 0.5712899
##
## Pearson's product-moment correlation
##
## data: y and x
## t = 19.377, df = 775, p-value < 2.2e-16
## alternative hypothesis: true correlation is not equal to 0
## 95 percent confidence interval:
## 0.5219282 0.6168381
## sample estimates:
## cor
## 0.5712899
確認ポイント: - 散布図の点の散らばりのパターンから、正・負・無相関のどれに見えるか? - 相関係数の値はどのくらいか?「強い」「中程度」「弱い」のどれにあたるか?
# ---------------------------------------------------------------
# 【t 検定とは?】
# 2つのグループの母平均に差があるかどうかを検定する手法。
#
# 【帰無仮説と対立仮説】
# H0(帰無仮説):私立と公立の卒業率の母平均は等しい
# H1(対立仮説):私立と公立の卒業率の母平均は異なる(両側検定)
#
# 【Welch の t 検定 vs Student の t 検定】
# R の t.test() はデフォルトで Welch の t 検定を行う。
# Welch の t 検定は「2グループの分散が等しいと仮定しない」検定で、
# 分散が異なる場合にも適用できる(より一般的で安全)。
#
# 【等分散の確認:Levene 検定】
# 分散が等しいかどうかは var.test() で確認できる。
# p値 < 0.05 → 等分散の仮説を棄却(→ Welch の t 検定を使う)
# p値 ≥ 0.05 → 等分散を仮定してよい(→ Student の t 検定も可)
# ---------------------------------------------------------------
# 2グループのデータを取り出す
# filter() : 条件を満たす行だけ抽出
# pull() : 指定した列をベクトルとして取り出す
grad_private <- college %>% filter(Private == "Yes") %>% pull(Grad.Rate)
grad_public <- college %>% filter(Private == "No") %>% pull(Grad.Rate)
# グループごとの件数と平均を再確認
cat("私立大学:", length(grad_private), "校 平均卒業率:",
round(mean(grad_private), 2), "%\n")## 私立大学: 565 校 平均卒業率: 69 %
## 公立大学: 212 校 平均卒業率: 56.04 %
## 平均の差(私立 - 公立): 12.96 ポイント
##
## F test to compare two variances
##
## data: grad_private and grad_public
## F = 1.3191, num df = 564, denom df = 211, p-value = 0.01852
## alternative hypothesis: true ratio of variances is not equal to 1
## 95 percent confidence interval:
## 1.048129 1.641039
## sample estimates:
## ratio of variances
## 1.319117
# ---------------------------------------------------------------
# 両側検定(two-sided)
# 「私立と公立で卒業率に差がある」かどうかを検定する。
# alternative = "two.sided" が両側検定(デフォルト)。
#
# 【結果の読み方】
# t 値 : 検定統計量(絶対値が大きいほど差が顕著)
# df : 自由度(Welch 検定では実数になることがある)
# p 値 : 帰無仮説が正しい場合にこの t 値以上が出る確率
# → p < 0.05 で「有意水準5%で帰無仮説を棄却」
# 95% CI : 平均の差の95%信頼区間
# ---------------------------------------------------------------
result_ttest <- t.test(
grad_private, # グループ1(私立)
grad_public, # グループ2(公立)
alternative = "two.sided", # 両側検定
var.equal = FALSE # 等分散を仮定しない(Welch の t 検定)
)
result_ttest # 結果を表示##
## Welch Two Sample t-test
##
## data: grad_private and grad_public
## t = 10.579, df = 431.97, p-value < 2.2e-16
## alternative hypothesis: true difference in means is not equal to 0
## 95 percent confidence interval:
## 10.54880 15.36276
## sample estimates:
## mean of x mean of y
## 68.99823 56.04245
# ---------------------------------------------------------------
# 【片側検定とは?】
# 「私立の卒業率は公立より高い」という一方向の仮説を検定する場合。
#
# alternative = "greater" : グループ1 > グループ2 の方向で検定
# alternative = "less" : グループ1 < グループ2 の方向で検定
#
# 片側検定は両側検定の p値の半分になるため、「有意になりやすい」。
# ただし、方向の仮説は分析前に理論的根拠をもとに立てる必要がある。
# 結果を見てから片側にするのは統計的に不正(p値の操作)。
# ---------------------------------------------------------------
# 「私立の卒業率 > 公立の卒業率」の片側検定
t.test(
grad_private,
grad_public,
alternative = "greater", # 私立 > 公立 の方向
var.equal = FALSE
)##
## Welch Two Sample t-test
##
## data: grad_private and grad_public
## t = 10.579, df = 431.97, p-value < 2.2e-16
## alternative hypothesis: true difference in means is greater than 0
## 95 percent confidence interval:
## 10.93711 Inf
## sample estimates:
## mean of x mean of y
## 68.99823 56.04245
# ---------------------------------------------------------------
# t 検定の結果をグラフで視覚化する
# エラーバー(平均 ± 1.96×標準誤差 ≒ 95%信頼区間)を追加することで
# 「差が有意かどうか」を視覚的に示す。
# 2つのエラーバーが重なっていない → 有意差がある可能性が高い
# ---------------------------------------------------------------
# グループ別の平均・標準誤差を計算
group_stats <- college %>%
group_by(Private) %>%
summarise(
mean_grad = mean(Grad.Rate),
se_grad = sd(Grad.Rate) / sqrt(n()), # 標準誤差 = SD / √n
n = n()
) %>%
mutate(
ci_lower = mean_grad - 1.96 * se_grad, # 95%CI 下限(近似)
ci_upper = mean_grad + 1.96 * se_grad # 95%CI 上限(近似)
)
ggplot(group_stats, aes(x = Private, y = mean_grad, fill = Private)) +
# 棒グラフ(平均値)
geom_bar(stat = "identity", width = 0.5, color = "black") +
# エラーバー(95%信頼区間)
geom_errorbar(
aes(ymin = ci_lower, ymax = ci_upper),
width = 0.15, linewidth = 0.8
) +
scale_fill_manual(values = c("No" = "lightcoral", "Yes" = "steelblue")) +
scale_x_discrete(labels = c("No" = "公立", "Yes" = "私立")) +
labs(
title = "私立・公立別の平均卒業率(エラーバー:95%信頼区間)",
subtitle = paste0("Welch t 検定 p 値 = ",
round(result_ttest$p.value, 4),
ifelse(result_ttest$p.value < 0.05,
" → 有意差あり(p < 0.05)",
" → 有意差なし(p ≥ 0.05)")),
x = "大学の種別",
y = "平均卒業率(%)"
) +
theme_bw() +
theme(legend.position = "none") +
# 有意差を示すブラケット(p < 0.05 の場合のみ追加)
{if (result_ttest$p.value < 0.05)
annotate("segment",
x = 1, xend = 2,
y = max(group_stats$ci_upper) + 2,
yend = max(group_stats$ci_upper) + 2,
linewidth = 0.8) } +
{if (result_ttest$p.value < 0.05)
annotate("text",
x = 1.5,
y = max(group_stats$ci_upper) + 3.5,
label = "*", size = 7) }t 検定の結果の読み方まとめ:
確認項目 値 解釈 t 値 10.579 正 → 私立の方が高い 自由度 432 Welch法による調整値 p 値 0 < 0.05 → 帰無仮説を棄却 平均の差の95%CI [10.55, 15.36] 0を含まない → 有意差あり
# ---------------------------------------------------------------
# 【単回帰分析とは?】
# 1つの説明変数(x)で目的変数(y)を予測する線形モデル。
# 数式:y = β0 + β1・x + ε
# β0 : 切片(x=0 のときの y の予測値)
# β1 : 回帰係数(x が1増えると y はどれだけ変わるか)
# ε : 誤差項(モデルで説明できない部分)
#
# 【lm() 関数の書き方】
# lm(目的変数 ~ 説明変数, data = データフレーム名)
# 「~」は「〜によって説明される」と読む。
#
# ここでは:Grad.Rate = β0 + β1・Outstate + ε
# 「卒業率は授業料によって説明される」という仮定のモデル。
# ---------------------------------------------------------------
# 線形回帰モデルを構築して「model1」に保存
model1 <- lm(Grad.Rate ~ Outstate, data = college)
# 結果の表示
summary(model1)##
## Call:
## lm(formula = Grad.Rate ~ Outstate, data = college)
##
## Residuals:
## Min 1Q Median 3Q Max
## -49.168 -9.114 -0.006 8.576 55.114
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 4.000e+01 1.408e+00 28.40 <2e-16 ***
## Outstate 2.439e-03 1.259e-04 19.38 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.11 on 775 degrees of freedom
## Multiple R-squared: 0.3264, Adjusted R-squared: 0.3255
## F-statistic: 375.5 on 1 and 775 DF, p-value: < 2.2e-16
# ---------------------------------------------------------------
# 【summary() の出力の読み方】
#
# Coefficients の表:
# Estimate : 推定された回帰係数(β̂0, β̂1)
# Std. Error : 標準誤差(係数の推定精度)
# t value : t 統計量(Estimate / Std. Error)
# Pr(>|t|) : p 値(係数が0でないかどうかの検定)
#
# モデル全体の指標:
# R-squared : 決定係数 → モデルが y のばらつきを何%説明しているか
# F-statistic : F 統計量 → 回帰モデル全体の有意性(後の ANOVA と同じ)
#
# 【回帰係数の解釈(例)】
# Outstate の Estimate が仮に 0.0015 なら:
# 「授業料が 1 ドル高い大学では、卒業率が平均 0.0015% 高い」
# ---------------------------------------------------------------
# 係数だけを取り出す
coef(model1)## (Intercept) Outstate
## 39.995114285 0.002439327
## 切片(β̂0): 39.9951
## Outstate の回帰係数(β̂1): 0.002439
##
## 解釈:授業料が 1,000 ドル上がると、卒業率は平均 2.439 % 変化する
# ---------------------------------------------------------------
# 回帰直線と残差(residuals)を可視化する
# 残差 = 実際の y - 予測した y
# 残差が小さいほどモデルのあてはまりが良い
# ---------------------------------------------------------------
# 予測値と残差をデータフレームに追加
college_aug <- college %>%
mutate(
fitted = fitted(model1), # 回帰モデルによる予測値
residuals = residuals(model1) # 残差(実測値 - 予測値)
)
# 散布図+回帰直線+残差の可視化
ggplot(college_aug, aes(x = Outstate, y = Grad.Rate)) +
# 残差を縦線で表示(実測値と予測値のずれ)
geom_segment(
aes(xend = Outstate, yend = fitted),
alpha = 0.2, color = "gray50"
) +
# データ点
geom_point(alpha = 0.4, size = 1.5, color = "steelblue") +
# 回帰直線
geom_line(aes(y = fitted), color = "red", linewidth = 1) +
labs(
title = "回帰直線と残差",
subtitle = paste0("Grad.Rate = ",
round(coef(model1)[1], 2), " + ",
round(coef(model1)[2], 5), " × Outstate",
" R2 = ", round(summary(model1)$r.squared, 3)),
x = "州外学生の授業料(ドル)",
y = "卒業率(%)"
) +
theme_bw()# ---------------------------------------------------------------
# 【残差診断とは?】
# 回帰分析の仮定(線形性・等分散性・正規性)が満たされているか
# 残差のグラフで確認する。これを「モデル診断」と呼ぶ。
#
# par(mfrow = c(2,2)) で4つのグラフを2×2に並べる。
# plot(model) で自動的に4種類の診断プロットが出る:
# 1. Residuals vs Fitted : 残差と予測値の関係(線形性の確認)
# 2. Normal Q-Q : 残差の正規性の確認
# 3. Scale-Location : 残差の等分散性の確認
# 4. Residuals vs Leverage: 影響力の大きい観測値の確認
# ---------------------------------------------------------------
par(mfrow = c(2, 2))
plot(model1)# ---------------------------------------------------------------
# 【ANOVA(分散分析)とは?】
# 「回帰モデル全体が統計的に意味があるか」を F 統計量で検定する。
#
# 考え方:目的変数 y のばらつき(総変動)を2つに分解する
# ・回帰変動(SS_R): 回帰モデルが「説明できた」ばらつき
# ・残差変動(SS_E): モデルが「説明できなかった」ばらつき
#
# F 統計量 = (回帰変動 / 回帰の自由度)÷(残差変動 / 残差の自由度)
# = 回帰の平均二乗 ÷ 残差の平均二乗
#
# F が大きい(=回帰で説明できた部分が大きい)
# → p 値が小さい → 「回帰モデルは有意」
#
# 【lm() → anova() の流れ】
# Rでは lm() でモデルを作った後、anova() に渡すだけで
# 分散分析表(ANOVA テーブル)が得られる。
# これは参考コードの disbud.trt → anova(disbud.trt) と同じ流れ。
# ---------------------------------------------------------------
# lm() で作ったモデルを anova() に渡す
anova_result <- anova(model1)
anova_result# ---------------------------------------------------------------
# ANOVA テーブルの各列の意味:
# Df : 自由度
# Sum Sq : 変動(平方和)
# Mean Sq : 平均二乗(= Sum Sq / Df)
# F value : F 統計量
# Pr(>F) : p 値(帰無仮説:回帰係数はすべて0)
#
# ここでは説明変数が1つ(Outstate)なので、
# t 検定の t 値の2乗が F 値と一致することも確認できる。
# ---------------------------------------------------------------
# t 値の二乗と F 値の比較
t_val <- summary(model1)$coefficients["Outstate", "t value"]
f_val <- anova_result$`F value`[1]
cat("回帰係数の t 値:", round(t_val, 4), "\n")## 回帰係数の t 値: 19.3775
## t 値の2乗(t²): 375.4869
## ANOVA の F 値 : 375.4869
## → 単回帰では t² = F が成立する
# ---------------------------------------------------------------
# 変動の分解をグラフで確認する
# 「総変動 = 回帰変動 + 残差変動」を積み上げ棒グラフで表現
# ---------------------------------------------------------------
ss_reg <- anova_result$`Sum Sq`[1] # 回帰変動(Outstate)
ss_res <- anova_result$`Sum Sq`[2] # 残差変動
ss_tot <- ss_reg + ss_res # 総変動
variation_df <- data.frame(
変動の種類 = c("回帰変動(SS_R)\n(モデルが説明できた部分)",
"残差変動(SS_E)\n(説明できなかった部分)"),
平方和 = c(ss_reg, ss_res),
割合 = c(ss_reg / ss_tot, ss_res / ss_tot)
)
ggplot(variation_df, aes(x = "卒業率の総変動", y = 平方和, fill = 変動の種類)) +
geom_bar(stat = "identity", width = 0.5, color = "black") +
scale_fill_manual(values = c("steelblue", "lightcoral")) +
geom_text(
aes(label = paste0(round(割合 * 100, 1), "%")),
position = position_stack(vjust = 0.5),
size = 5, color = "white", fontface = "bold"
) +
labs(
title = "ANOVA による変動の分解",
subtitle = paste0("R2 = ", round(summary(model1)$r.squared, 3),
" (回帰変動が総変動の",
round(summary(model1)$r.squared * 100, 1), "% を占める)"),
x = "",
y = "平方和",
fill = ""
) +
theme_bw() +
theme(legend.position = "bottom")# ---------------------------------------------------------------
# 【重回帰分析とは?】
# 説明変数を複数加えたモデル。
# 数式:y = β0 + β1・x1 + β2・x2 + ... + ε
#
# ANOVA は「モデルAとモデルBを比較して、変数を追加した意味があるか」
# を検定する際にも使える(モデル比較の ANOVA)。
#
# ここでは:
# model1 : Grad.Rate ~ Outstate(単回帰)
# model2 : Grad.Rate ~ Outstate + Expend(重回帰)
# model3 : Grad.Rate ~ Outstate + Expend + Private(質的変数を追加)
# の3モデルを比較する。
# ---------------------------------------------------------------
# モデル2:説明変数に Expend(学生一人当たり支出)を追加
model2 <- lm(Grad.Rate ~ Outstate + Expend, data = college)
# モデル3:さらに Private(質的変数)を追加
model3 <- lm(Grad.Rate ~ Outstate + Expend + Private, data = college)
# 各モデルの結果確認
summary(model2)##
## Call:
## lm(formula = Grad.Rate ~ Outstate + Expend, data = college)
##
## Residuals:
## Min 1Q Median 3Q Max
## -49.031 -9.130 -0.019 8.473 55.152
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.998e+01 1.411e+00 28.331 <2e-16 ***
## Outstate 2.408e-03 1.702e-04 14.143 <2e-16 ***
## Expend 3.601e-05 1.312e-04 0.275 0.784
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.12 on 774 degrees of freedom
## Multiple R-squared: 0.3264, Adjusted R-squared: 0.3247
## F-statistic: 187.6 on 2 and 774 DF, p-value: < 2.2e-16
##
## Call:
## lm(formula = Grad.Rate ~ Outstate + Expend + Private, data = college)
##
## Residuals:
## Min 1Q Median 3Q Max
## -48.239 -8.986 0.100 8.422 54.754
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 3.985e+01 1.418e+00 28.112 <2e-16 ***
## Outstate 2.312e-03 2.008e-04 11.517 <2e-16 ***
## Expend 5.801e-05 1.335e-04 0.435 0.664
## PrivateYes 1.245e+00 1.388e+00 0.897 0.370
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 14.12 on 773 degrees of freedom
## Multiple R-squared: 0.3271, Adjusted R-squared: 0.3245
## F-statistic: 125.3 on 3 and 773 DF, p-value: < 2.2e-16
# ---------------------------------------------------------------
# anova() に複数のモデルを渡すと「モデル比較の ANOVA」ができる。
# F 検定により「変数を追加した効果が有意かどうか」を確認できる。
# p値 < 0.05 → 変数を追加した効果が有意(モデルが改善された)
# ---------------------------------------------------------------
# モデル1 vs モデル2(Expend を追加した効果)
anova(model1, model2)# ---------------------------------------------------------------
# 3つのモデルの指標をまとめて比較する表
# ---------------------------------------------------------------
model_comp <- data.frame(
モデル = c("model1", "model2", "model3"),
説明変数 = c("Outstate", "Outstate + Expend",
"Outstate + Expend + Private"),
R2 = round(c(summary(model1)$r.squared,
summary(model2)$r.squared,
summary(model3)$r.squared), 4),
自由度調整済みR2 = round(c(summary(model1)$adj.r.squared,
summary(model2)$adj.r.squared,
summary(model3)$adj.r.squared), 4),
F値 = round(c(summary(model1)$fstatistic[1],
summary(model2)$fstatistic[1],
summary(model3)$fstatistic[1]), 2),
残差標準誤差 = round(c(summary(model1)$sigma,
summary(model2)$sigma,
summary(model3)$sigma), 3)
)
knitr::kable(model_comp,
caption = "モデル比較(R2・F値・残差標準誤差)",
align = c("l","l","r","r","r","r"))| モデル | 説明変数 | R2 | 自由度調整済みR2 | F値 | 残差標準誤差 |
|---|---|---|---|---|---|
| model1 | Outstate | 0.3264 | 0.3255 | 375.49 | 14.108 |
| model2 | Outstate + Expend | 0.3264 | 0.3247 | 187.56 | 14.116 |
| model3 | Outstate + Expend + Private | 0.3271 | 0.3245 | 125.27 | 14.118 |
モデル比較のポイント:
- R2(決定係数) : 値が大きいほど当てはまりが良い(ただし変数を増やすと自動的に上がる)
- 調整済みR2 : 変数の数のペナルティを考慮。モデル選択の基準として推奨
- ANOVA(モデル比較)のp値 : 変数を追加した効果が偶然かどうかを検定
# ---------------------------------------------------------------
# 分析結果を口頭発表・レポートで使えるように整理する
# ---------------------------------------------------------------
cat("====================================================\n")## ====================================================
## 分析結果サマリー
## ====================================================
## 【1. 記述統計】
## 卒業率の平均:10440.7% 中央値:9990.0%
## 標準偏差:4023.0 ポイント IQR:5605.0 ポイント
## 【2. t 検定(私立 vs 公立)】
## 私立平均:69.0% 公立平均:56.0%
cat(sprintf(" t = %.3f, df = %.1f, p = %.4f\n",
result_ttest$statistic,
result_ttest$parameter,
result_ttest$p.value))## t = 10.579, df = 432.0, p = 0.0000
cat(sprintf(" → %s(有意水準5%%)\n\n",
ifelse(result_ttest$p.value < 0.05,
"有意差あり:私立の卒業率は公立より有意に高い",
"有意差なし:私立・公立で卒業率に差はない")))## → 有意差あり:私立の卒業率は公立より有意に高い(有意水準5%)
## 【3. 単回帰分析(Outstate → Grad.Rate)】
## 切片:39.995 回帰係数:0.002439
cat(sprintf(" R2 = %.3f → Outstate は卒業率の変動の%.1f%%を説明\n",
summary(model1)$r.squared,
summary(model1)$r.squared * 100))## R2 = 0.326 → Outstate は卒業率の変動の32.6%を説明
cat(sprintf(" F(1, %d) = %.2f, p = %.2e\n\n",
anova_result$Df[2],
anova_result$`F value`[1],
anova_result$`Pr(>F)`[1]))## F(1, 775) = 375.49, p = 1.63e-68
## 【4. ANOVA によるモデル比較】
cat(sprintf(" model1 R2 = %.3f → model3 R2 = %.3f\n",
summary(model1)$r.squared, summary(model3)$r.squared))## model1 R2 = 0.326 → model3 R2 = 0.327
## Expend, Private の追加でモデルが有意に改善した
## ====================================================
作成:久保田貴文(多摩大学)