はじめに
今回は統計検定2級の範囲の水準間平方和、残差平方和に関して学びます。分散分析(ANOVA)を勉強していると出てくる「水準間平方和」と「残差平方和」。 なんだコレって、なったので記事にしています。
✅ 「分散分析」って何?
複数のグループの平均値に差があるかどうかを調べる統計手法です。
たとえば:
- A社、B社、C社の平均売上に差があるか?
- 3種類の薬の効果に違いがあるか?
🟦 水準間平方和とは?
✔ グループどうしの「平均の差」
水準間平方和は、「グループの平均値が、全体平均からどれくらいズレているか」を表します。
つまり、「グループ間に差があるか?」を数値化するためのものです。
✔ 具体例でイメージ!
クラス | 平均点 | 全体平均との差 | 差の2乗 × 人数 |
---|---|---|---|
A | 60点 | -10点 | 10² × 3 = 300 |
B | 80点 | +10点 | 10² × 2 = 200 |
水準間平方和 = 300 + 200 = 500
✔ 数式で書くと
$$
\text{水準間平方和} = \sum_{j=1}^{k} n_j (\bar{y}_j - \bar{y})^2
$$
- $k$:グループの数
- $n_j$:グループ $j$ のデータ数
- $\bar{y}_j$:グループ $j$ の平均
- $\bar{y}$:全体の平均
✔ 名前の意味を分解すると
用語 | 意味 |
---|---|
水準 | グループ(例:クラスや商品タイプなど) |
間 | グループとグループの“あいだ” |
平方 | 差を2乗する(マイナスを打ち消すため) |
和 | 全部足す |
🟨 残差平方和とは?
✔ 同じグループ内での「ばらつき」
残差平方和は、「各データが、そのグループの平均からどれだけズレているか」を表します。
つまり、「グループ内で点数がバラついているか?」を数値で見ます。
✔ 「残差」ってなに?
残差= 実際の値 − グループの平均
たとえば:
学生 | クラス | 点数 | クラス平均 | 残差 |
---|---|---|---|---|
A | 1組 | 70点 | 60点 | +10点 |
B | 1組 | 50点 | 60点 | -10点 |
残差平方和は、この残差の2乗を全部足したものです。
✔ 数式で書くと
$$
\text{残差平方和} = \sum_{j=1}^{k} \sum_{i=1}^{n_j} (y_{ij} - \bar{y}_j)^2
$$
- $y_{ij}$:グループ $j$ の $i$ 番目のデータ
- $\bar{y}_j$:グループの平均
✔ 名前の意味を分解すると
用語 | 意味 |
---|---|
残差 | 実際の値と、グループ平均の差 |
平方 | 差を2乗する(マイナスを打ち消すため) |
和 | 全部足す |
🔁 2つの平方和の違いまとめ
用語 | 見ているもの |
---|---|
水準間平方和 | グループどうしの平均の差 |
残差平方和 | グループ内のばらつき(ズレ) |
🔧 全体の関係式
分散分析では、全体のバラつき(全体平方和)を次のように分けます:
$$
\text{全体平方和(SST)} = \text{水準間平方和(SSB)} + \text{残差平方和(SSE)}
$$
✅ 問題
ある学校で、A組・B組・C組の3クラスについて、テストの点数を以下のように調査しました。
クラス | 点数 |
---|---|
A組 | 60, 65, 70 |
B組 | 80, 75 |
C組 | 50, 55, 60 |
このデータをもとに、以下の値を求めなさい。
❓ 計算するもの
- 各クラスの平均点、および全体の平均点
- 水準間平方和(SSB)
- 残差平方和(SSE)
🧮 解き方と解説:水準間平方和・残差平方和の計算
✅ ステップ①:各クラスと全体の平均を出す
クラス | 点数 | 合計 | 人数 | 平均 |
---|---|---|---|---|
A組 | 60, 65, 70 | 195 | 3 | 65.0 |
B組 | 80, 75 | 155 | 2 | 77.5 |
C組 | 50, 55, 60 | 165 | 3 | 55.0 |
全体 | 合計 = 195 + 155 + 165 = 515 | 合計 = 8人 | 全体平均 = 515 ÷ 8 = 64.375 |
✅ ステップ②:水準間平方和(SSB)を求める
$$
SSB = \sum_{j=1}^{k} n_j (\bar{y}_j - \bar{y})^2
$$
- A組:$3 \times (65.0 - 64.375)^2 = 3 \times (0.625)^2 = 1.171875$
- B組:$2 \times (77.5 - 64.375)^2 = 2 \times (13.125)^2 = 344.53125$
- C組:$3 \times (55.0 - 64.375)^2 = 3 \times (-9.375)^2 = 263.671875$
合計:
$$
SSB = 1.171875 + 344.53125 + 263.671875 = \mathbf{609.375}
$$
✅ ステップ③:残差平方和(SSE)を求める
$$
SSE = \sum_{j=1}^{k} \sum_{i=1}^{n_j} (y_{ij} - \bar{y}_j)^2
$$
各クラスで計算:
-
A組(平均65)
$(60 - 65)^2 + (65 - 65)^2 + (70 - 65)^2 = 25 + 0 + 25 = 50$ -
B組(平均77.5)
$(80 - 77.5)^2 + (75 - 77.5)^2 = 6.25 + 6.25 = 12.5$ -
C組(平均55)
$(50 - 55)^2 + (55 - 55)^2 + (60 - 55)^2 = 25 + 0 + 25 = 50$
合計:
$$
SSE = 50 + 12.5 + 50 = \mathbf{112.5}
$$
✅ 最終結果まとめ
指標 | 値 |
---|---|
全体平均 | 64.375 |
水準間平方和 SSB | 609.375 |
残差平方和 SSE | 112.5 |
✅ 補足:全体平方和も求められる
$$
SST = SSB + SSE = 609.375 + 112.5 = \mathbf{721.875}
$$
# 📌 日本語フォントインストール(Google Colab専用)
!apt-get -y install fonts-ipafont-gothic > /dev/null
# ライブラリのインポート
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.font_manager import FontProperties
# 日本語フォント設定(明示的に使用)
jp_font = FontProperties(fname="/usr/share/fonts/opentype/ipafont-gothic/ipag.ttf")
# データ定義
data = {
'A': [60, 65, 70],
'B': [80, 75],
'C': [50, 55, 60]
}
# 平均・全体平均
class_means = {k: np.mean(v) for k, v in data.items()}
all_scores = [score for scores in data.values() for score in scores]
overall_mean = np.mean(all_scores)
class_sizes = {k: len(v) for k, v in data.items()}
# 平方和計算
ssb = sum(class_sizes[k] * (class_means[k] - overall_mean) ** 2 for k in data)
sse = sum((score - class_means[k]) ** 2 for k, scores in data.items() for score in scores)
sst = ssb + sse
# 結果表示
print("【各クラスの平均】")
for k in data:
print(f"{k}組の平均: {class_means[k]:.3f} 点")
print(f"\n【全体の平均】: {overall_mean:.3f} 点")
print(f"\n【水準間平方和 (SSB)】: {ssb:.3f}")
print(f"【残差平方和 (SSE)】: {sse:.3f}")
print(f"【全体平方和 (SST)】: {sst:.3f}")
# グラフ描画
fig, ax = plt.subplots(figsize=(10, 6))
colors = {'A': 'skyblue', 'B': 'salmon', 'C': 'lightgreen'}
x_pos = 0
xticks = []
xtick_labels = []
for group, scores in data.items():
xs = np.arange(x_pos, x_pos + len(scores))
ys = scores
ax.scatter(xs, ys, color=colors[group], label=f"{group}組の点数", zorder=3)
ax.hlines(class_means[group], xmin=xs[0]-0.3, xmax=xs[-1]+0.3,
color=colors[group], linestyle='--', label=f"{group}組 平均: {class_means[group]:.1f}点")
x_pos += len(scores) + 1
xticks.extend(xs)
xtick_labels.extend([f"{group}{i+1}" for i in range(len(scores))])
# 全体平均線
ax.hlines(overall_mean, xmin=-1, xmax=x_pos-1, color='black',
linestyle=':', linewidth=2, label=f"全体平均: {overall_mean:.1f}点")
# ラベル設定(すべて fontproperties=jp_font を明示)
ax.set_xticks(xticks)
ax.set_xticklabels(xtick_labels, rotation=45, fontproperties=jp_font)
ax.set_ylabel("点数", fontproperties=jp_font)
ax.set_title("各クラスの点数と平均(分散分析のイメージ)", fontproperties=jp_font)
ax.legend(prop=jp_font)
ax.grid(True)
plt.tight_layout()
plt.show()
【各クラスの平均】
A組の平均: 65.000 点
B組の平均: 77.500 点
C組の平均: 55.000 点
【全体の平均】: 64.375 点
【水準間平方和 (SSB)】: 609.375
【残差平方和 (SSE)】: 112.500
【全体平方和 (SST)】: 721.875
これで、水準間平方和、残差平方和が理解できました。ただ、この値出てきてなんなの??🤔って感じですね。
結局ここの値から何か示唆が得られていないので、このままではなんの価値もない値です。なので、次はF検定を学ぼうと思います!!