論文一覧に戻る 📚 用語集トップ 🗺 概念マップ
📚 用語解説(ジャストインタイム型データサイエンス教育)
分散分析(ANOVA)
Analysis of Variance
3群以上の平均比較 — t検定の自然な拡張
仮説検定群間比較F分布実験計画法

🔖 キーワード索引

anova」は統計データ分析の文脈で扱う重要概念のひとつ。 本ページでは「anova」を取り巻く中核キーワードを以下にチップで一覧化する。 各キーワードは関連する概念・手法・道具立てを含み、 文献検索や学習計画の起点になる。

anova統計分析SSDSE-B-2026前提条件適用範囲落とし穴関連手法Python 実装検証方法

これらのキーワードは「anova の理解 → 適用 → 検証」のプロセスを構成する。 各章で詳しく解説する。

💡 30秒で分かる結論

🍰 まずはやさしく

3つ以上のグループを比べる道具です。

平均に差があるか調べるために使います。

部活ごとの練習時間の違いを調べます。

分析の種類や結果の見方を学びます。

📍 あなたが今見ているもの

🍰 まずはやさしく

グループの平均を比べる方法です。

データのばらつきから差を判定します。

スマホの機種による利用時間を比べます。

分析の手順と使い分けを解説します。

本ページでは、 分散分析 (ANOVA)を統合的に解説します。 一元配置二元配置反復測定post-hoc 検定効果量を一気通貫で扱います。

ANOVA は「3 群以上の平均が等しいか」を検定する手法。 名前は「分散」ですが、 検定対象は平均値です。 群内変動と群間変動を比較することから「分散」と呼ばれます。

🎨 直感で掴む — ANOVAの本質

🍰 まずはやさしく

ばらつきを切り分けるイメージです。

差が本物かどうかを判断するために使います。

クラスごとのテスト点数の差を調べます。

ばらつきの比率で考える仕組みを学びます。

ANOVA(分散分析)の核心は名前のとおり 「分散の分解」。 SSDSE-B-2026 で 47 都道府県を 北日本・東日本・西日本 の 3 ブロックに分けて出生率を比較するとき、 「全体のバラつき」を 群間のバラつき(地域差)群内のバラつき(地域内の差) に切り分け、 その比率(F値)で「地域差は本物か」を検定します。

比喩で言うと、 ある楽団の演奏のばらつきを「楽器セクション間のばらつき」と「同じセクション内のばらつき」に切り分けて、 もしセクション間のバラつきが圧倒的に大きければ「セクションごとに本当に差がある」と判断するイメージ。 ANOVAは t検定の自然な拡張で、 群が 3 つ以上のときに 多重比較の罠 を避けながら一発で検定できる点が魅力です。

🎮 触って理解する — 分散の比で平均の差を検定する

3 群(A・B・C)の平均を 3 本のスライダーで、 群内のばらつき(標準偏差)を 1 本のスライダーで動かしてみましょう。 群間平方和 SSbetween・群内平方和 SSwithin・自由度・F 統計量p 値がリアルタイムで再計算されます。 群間の平均差が大きいほど、 また群内のばらつきが小さいほど F は大きく p は小さくなる —— これが「分散の比で平均の差を検定する」という ANOVA の核心です(各群 n = 8、 k = 3 群、 全体 N = 24 で固定)。

各群の観測値(点)・群平均(実線)・全体平均(破線)
F 分布 F(2, 21)・棄却域(赤, α=0.05)・観測 F(縦線)

💡 体感ポイント: 3 つの平均を近づけると SSbetween が縮み F が 1 に近づいて p が大きくなります(=差なし)。 逆に 1 群だけ大きく離すと SSbetween が伸びて F が跳ね上がり、 観測 F が右側の赤い棄却域へ入って p < 0.05 になります。 σ(群内ばらつき)を上げると分母 MSwithin が増えて同じ平均差でも F が下がる —— 「シグナル(群間差)÷ ノイズ(群内差)」という F 比の意味がそのまま見えます。

この体験と直結する概念: t 検定(2 群版 ANOVA・F = t²)/ 効果量 η²(= SSbetween/SStotal、 差の実質的大きさ)/ 多重比較多重検定(有意後に Tukey HSD でどの群ペアが違うか特定)/ F 検定仮説検定。 なお F 検定は正規性・等分散性・独立性を前提とし、 崩れる場合は Kruskal–Wallis や Welch ANOVA を用います。

📐 7. 効果量

🍰 まずはやさしく

差の大きさを表す数値のことです。

平均の差がどれだけ重要かを知るために使います。

買い物への影響度が強いか調べます。

効果量の計算方法と基準を学びます。

ANOVA の効果量:

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 B4101(年平均気温) 北海道 11.0 東京都 17.6 沖縄県 23.8 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import numpy as np
import pandas as pd
from scipy import stats

# ── この抜粋だけで動くように、8 地方ブロック別の年平均気温を用意する ──
# 英字の項目コード(A1101 など)を使うので、2 行目の日本語名は読み飛ばす
_df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_df = _df[_df['SSDSE-B-2026'] == 2023]          # 最新年度の 47 都道府県
# 「地方ブロック」は SSDSE に無い列なので、都道府県名から 8 区分を作る
_BLOCKS = {
    '北海道': ['北海道'],
    '東北': ['青森県', '岩手県', '宮城県', '秋田県', '山形県', '福島県'],
    '関東': ['茨城県', '栃木県', '群馬県', '埼玉県', '千葉県', '東京都', '神奈川県'],
    '中部': ['新潟県', '富山県', '石川県', '福井県', '山梨県', '長野県',
             '岐阜県', '静岡県', '愛知県'],
    '近畿': ['三重県', '滋賀県', '京都府', '大阪府', '兵庫県', '奈良県', '和歌山県'],
    '中国': ['鳥取県', '島根県', '岡山県', '広島県', '山口県'],
    '四国': ['徳島県', '香川県', '愛媛県', '高知県'],
    '九州': ['福岡県', '佐賀県', '長崎県', '熊本県', '大分県', '宮崎県',
             '鹿児島県', '沖縄県'],
}
_R = {p: g for g, ps in _BLOCKS.items() for p in ps}
_df = _df.assign(block=_df['Prefecture'].map(_R),
                 temp=pd.to_numeric(_df['B4101'], errors='coerce'))   # 年平均気温(℃)
# groups = 「ブロックごとの年平均気温の配列」のリスト(8 群)
groups = [g['temp'].values for _, g in _df.groupby('block', sort=False)]

def eta_squared(groups):
    grand = np.mean(np.concatenate(groups))
    ss_b = sum(len(g)*(np.mean(g)-grand)**2 for g in groups)
    ss_t = sum(((np.concatenate(groups)-grand)**2))
    return ss_b / ss_t
F, p = stats.f_oneway(*groups)
grand = np.mean(np.concatenate(groups))
ss_b = sum(len(g) * (np.mean(g) - grand) ** 2 for g in groups)
ss_t = sum((np.concatenate(groups) - grand) ** 2)
print(f'F統計量 = {F:.3f}, p値 = {p:.3g}')
print(f'群間平方和 = {ss_b:.1f}, 群内平方和 = {ss_t - ss_b:.1f}')
print(f'η² = {eta_squared(groups):.3f}')
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地方ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) F統計量 = 13.383, p値 = 1.18e-08 群間平方和 = 136.2, 群内平方和 = 56.7 η² = 0.706
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

📋 8. 前提条件

前提 確認方法 違反したら
残差の正規性QQプロット・ShapiroKruskal–Wallis
等分散性Levene 検定Welch's ANOVA
独立性サンプリング設計混合効果モデル
球面性 (反復測定)Mauchly検定Greenhouse–Geisser補正

🔄 9. ノンパラメトリック代替

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
1
2
3
from scipy import stats
H, p = stats.kruskal(*groups)
print(f'Kruskal-Wallis H = {H:.3f}, p = {p:.4f}')
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) Kruskal-Wallis H = 31.650, p = 0.0000
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

🔬 数式を言葉で読み解く — 分散分解と F値

$$ \text{SS}_{\text{total}} = \text{SS}_{\text{between}} + \text{SS}_{\text{within}}, \quad F = \frac{\text{SS}_{\text{between}}/(k-1)}{\text{SS}_{\text{within}}/(N-k)} = \frac{\text{MS}_{\text{between}}}{\text{MS}_{\text{within}}} $$
記号意味SSDSE-B-2026 例
$k$群数3 地域ブロック
$N$総サンプル数47 都道府県
$\text{SS}_{\text{between}}$群間平方和(地域差)地域ブロックの平均出生率のバラつき
$\text{SS}_{\text{within}}$群内平方和(誤差)同じブロック内の県間バラつき
$F$「シグナル/ノイズ」比1 を大幅に超えれば群差あり

有意になったら post-hoc 検定(Tukey HSDなど) で「どの群間に差があるか」を特定し、 効果量 $\eta^2 = \text{SS}_{\text{between}}/\text{SS}_{\text{total}}$ を必ず併記します。

🧮 SSDSE-B 実値計算例:地域ブロックで「食料費」に差があるか?

SSDSE-B-2026(47都道府県、 2023年)で、 都道府県を北海道・東北・関東・中部・近畿・中国・四国・九州沖縄の8地域に分け、 食料費(L322101、 二人以上の世帯、 円)に地域差があるかを一元配置 ANOVA で確認します。

📊 ステップ1:群分け

地域 県数 食料費平均(円) 標準偏差
北海道174,341
東北680,8242,844
関東786,6708,305
中部982,1824,771
近畿783,0844,028
中国578,1774,225
四国475,8213,792
九州沖縄875,8422,844

※実値は SSDSE-B-2026(2023年)から集計。 ANOVA の主結果は F(7, 39) = 4.09、 p = 0.0019、 η² = 0.42。 「地域は食料費に影響あり」を示唆。

📊 ステップ2:事後検定(Tukey HSD)

有意な ANOVA が出ても、 どの地域ペアが違うかは分かりません。 Tukey HSD で全ペアを比較すると、 「関東 vs 九州沖縄」(差 = 10,828 円, p = 0.002)と「関東 vs 四国」(差 = 10,849 円, p = 0.019)が有意(p < 0.05)で、 「食料費が高い関東と、 低めの四国・九州沖縄で差が大きい」構造が浮かびます。

📊 ステップ3:効果量 η² と実質的意味

η² = 0.42 は「食料費の総変動のうち、 42% が地域差で説明できる」と読みます。 Cohen 基準では η² > 0.14 が「大きい効果」なので、 統計的にも実質的にも大きな地域差と結論できます。

🧮 数式に値を入れて手で計算する

合成データ (3 群、 各 $n=4$) を一元配置 ANOVA の数式に代入し、 Step 1〜6 で SS / MS / F / p を手計算する。 同じ計算を Python (scipy.stats.f_oneway) で再現し、 結果が完全一致することを確認する。

📐 一元配置 ANOVA (再掲)

$$ F = \frac{MS_\text{between}}{MS_\text{within}} = \frac{SS_\text{between}/(k-1)}{SS_\text{within}/(N-k)} $$

ただし $SS_\text{between} = \sum_{j=1}^{k} n_j (\bar{x}_j - \bar{x})^2$、 $SS_\text{within} = \sum_{j=1}^{k}\sum_{i=1}^{n_j}(x_{ij} - \bar{x}_j)^2$。

Step 1: データ準備 (3 群、 各 $n=4$)

観測値$n_j$群平均 $\bar{x}_j$
A4, 6, 5, 545.0
B7, 8, 6, 747.0
C9, 11, 10, 10410.0
全体$N=12$$\bar{x} = (5+7+10) \cdot 4 / 12 = 7.333333$

Step 2: 群内平方和 $SS_\text{within}$ (各群内の偏差平方の合計)

$x_{ij} - \bar{x}_j$$(x_{ij}-\bar{x}_j)^2$ の合計
A (mean=5)$-1, +1, 0, 0$$1+1+0+0 = 2$
B (mean=7)$0, +1, -1, 0$$0+1+1+0 = 2$
C (mean=10)$-1, +1, 0, 0$$1+1+0+0 = 2$
$SS_\text{within}$$2 + 2 + 2 = 6$

Step 3: 群間平方和 $SS_\text{between}$ ($\bar{x} = 22/3 = 7.333333$)

$\bar{x}_j - \bar{x}$$n_j (\bar{x}_j - \bar{x})^2$
A$5 - 22/3 = -7/3$$4 \times (7/3)^2 = 196/9$
B$7 - 22/3 = -1/3$$4 \times (1/3)^2 = 4/9$
C$10 - 22/3 = +8/3$$4 \times (8/3)^2 = 256/9$
$SS_\text{between}$$(196+4+256)/9 = 456/9 \approx 50.666667$

Step 4: 自由度

項目計算結果
$df_\text{between} = k - 1$$3 - 1$2
$df_\text{within} = N - k$$12 - 3$9

Step 5: 平均平方 (MS) と F 値

項目計算結果
$MS_\text{between}$$50.666667 / 2$25.333333
$MS_\text{within}$$6 / 9$0.666667
$F$$25.333333 / 0.666667$38.000000

Step 6: p 値と結論

項目結果
$F(2, 9)$ 分布の上側確率$p \approx 0.0000409$
有意水準 $\alpha = 0.05$ で判定$p < 0.05$ → 3 群の母平均は等しくない

🐍 同じ計算を Python で再現

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import numpy as np
from scipy import stats

# Step 1: 合成データ (3 群、 各 n=4)
A = np.array([4, 6, 5, 5])
B = np.array([7, 8, 6, 7])
C = np.array([9, 11, 10, 10])
groups = [A, B, C]
all_data = np.concatenate(groups)

k = len(groups)
N = len(all_data)
grand_mean = all_data.mean()

# Step 2: SS_within
ss_within = sum(((g - g.mean())**2).sum() for g in groups)

# Step 3: SS_between
ss_between = sum(len(g) * (g.mean() - grand_mean)**2 for g in groups)

# Step 4: df
df_b = k - 1
df_w = N - k

# Step 5: MS と F
ms_b = ss_between / df_b
ms_w = ss_within / df_w
F = ms_b / ms_w

# Step 6: p 値
p = 1 - stats.f.cdf(F, df_b, df_w)

print(f"grand_mean   = {grand_mean:.6f}")
print(f"SS_within    = {ss_within}")
print(f"SS_between   = {ss_between:.6f}")
print(f"df_between   = {df_b}, df_within = {df_w}")
print(f"MS_between   = {ms_b:.6f}")
print(f"MS_within    = {ms_w:.6f}")
print(f"F            = {F:.6f}")
print(f"p-value      = {p:.7f}")

# 検算: scipy.stats.f_oneway
F2, p2 = stats.f_oneway(A, B, C)
print(f"scipy F      = {F2:.6f}, p = {p2:.7f}")

📤 実行結果

grand_mean = 7.333333 SS_within = 6.0 SS_between = 50.666667 df_between = 2, df_within = 9 MS_between = 25.333333 MS_within = 0.666667 F = 38.000000 p-value = 0.0000409 scipy F = 38.000000, p = 0.0000409

💬 手計算 (Step 2〜6) と Python 出力 (および scipy.stats.f_oneway の検算) が完全一致 ($F = 38.000$、 $p \approx 4.09 \times 10^{-5}$)。 群内ばらつきが小さく群間ばらつきが大きいため、 $\alpha = 0.05$ で「3 群の母平均は等しい」を棄却できる。

🐍 13. ライブラリ早見表

🐍 13. ライブラリ早見表

用途 関数
一元配置ANOVAscipy.stats.f_oneway
二元配置ANOVAstatsmodels.formula.api.ols + anova_lm
反復測定ANOVAstatsmodels.stats.anova.AnovaRM
Welch's ANOVApingouin.welch_anova
Tukey HSDstatsmodels.stats.multicomp.pairwise_tukeyhsd
Bonferronistatsmodels.stats.multitest.multipletests(method='bonferroni')
Kruskal–Wallisscipy.stats.kruskal
Friedmanscipy.stats.friedmanchisquare

📜 14. ANOVA の歴史

💼 15. 実務応用

📋 16. ANOVA 表の読み方

statsmodels の anova_lm が出力する表の各列:

意味
sum_sq平方和 SS。 各要因の説明する変動
df自由度。 K-1(要因)、 N-K(残差)
FF統計量 = MS要因 / MS残差
PR(>F)F値以上の値が出る確率(p値)

SS の3タイプ(不均衡データで違いが出る)

🔗 17. ANOVA と回帰の等価性

ANOVA は実は「カテゴリ変数(ダミー変数)だけの線形回帰」と数学的に等価。 statsmodels では同じ ols で記述できる。

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) C5401(標準価格(平均価格)(住宅地)) 北海道 5,092,000 23,600 東京都 14,086,000 404,400 沖縄県 1,468,000 68,100 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
import pandas as pd
import statsmodels.formula.api as smf
import statsmodels.api as sm

# ── この抜粋だけで動くように、都市規模つきの表を用意する ──
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()      # 最新年度の 47 都道府県
# 「都市規模」は SSDSE に無い列なので、総人口を 3 等分して作る
df['都市規模'] = pd.qcut(df['A1101'], 3, labels=['小', '中', '大'])
df['C5401'] = pd.to_numeric(df['C5401'], errors='coerce')   # 標準地価(住宅地)
df = df.dropna(subset=['C5401'])

# ANOVA としての記述
# 数式に C(...) と書くとカテゴリ扱いになるが、このページでは前の例で
# 変数 C を作っているため C() が上書きされてしまう。
# 都市規模は category 型なので、そのまま書けばカテゴリとして扱われる。
m_anova = smf.ols('C5401 ~ 都市規模', data=df).fit()  # C5401=標準地価(住宅地)
print(sm.stats.anova_lm(m_anova, typ=2))

# 同じモデルを「ダミー回帰」として見る
print(m_anova.summary())
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) sum_sq df F PR(>F) 都市規模 5.459536e+10 2.0 8.832652 0.000596 Residual 1.359838e+11 44.0 NaN NaN OLS Regression Results ============================================================================== Dep. Variable: C5401 R-squared: 0.286 Model:
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

p値・F値は完全に一致する。 ANOVA の「カテゴリの主効果」が、 回帰の「ダミー係数の合同検定」に対応している。

✅ 18. ANOVA 実施チェックリスト

❓ 19. よくある質問

Q. 2 群のときに ANOVA を使ってもよい?

A. はい。 2 群 ANOVA は 2 標本 t検定(等分散仮定)と完全に等価です(F = t²、 df の関係も対応)。 ただし慣例的に 2 群なら t検定を使います。

Q. ANOVA が有意でも post-hoc が一つも有意でないことがある?

A. あります。 ANOVA は「全体的な差」、 post-hoc は「ペアごとの差」を見るため、 補正の保守性で起こり得ます。 効果量と CI で全体像を補完しましょう。

Q. 共変量を入れたいときは?

A. ANCOVA(共分散分析)を使います。 statsmodels では ols('y ~ C(group) + covariate', data=df) のように共変量を加えるだけです。

Q. 反復測定で時点が多いとき球面性が問題になります

A. Mauchly 検定で確認、 違反していたら Greenhouse–Geisser や Huynh–Feldt 補正を使います。 または混合効果モデルに切り替える選択肢もあります。

① scipy.stats.f_oneway(最もシンプル)

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行) 都道府県 A1101(総人口) A1303(65歳以上人口) 北海道 5,092,000 1,681,000 東京都 14,086,000 3,205,000 沖縄県 1,468,000 350,000 …(全 47 行)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pandas as pd
from scipy import stats

# ── この抜粋だけで動くように、3 群のデータを用意する ──
# 47 都道府県を総人口で 3 等分し、それぞれの高齢化率を 1 群とする
_a = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_a = _a[_a['SSDSE-B-2026'] == 2023].copy()
_a['aging'] = _a['A1303'] / _a['A1101'] * 100
_a['規模'] = pd.qcut(_a['A1101'], 3, labels=['小', '中', '大'])
group_a = _a.loc[_a['規模'] == '小', 'aging'].values
group_b = _a.loc[_a['規模'] == '中', 'aging'].values
group_c = _a.loc[_a['規模'] == '大', 'aging'].values

# 3群を直接渡す
F, p = stats.f_oneway(group_a, group_b, group_c)
print(f"F={F:.3f}, p={p:.4f}")
# Welch 版(等分散仮定なし)は alexandergovern を使う
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) F=12.128, p=0.0001
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

② statsmodels(事後検定・効果量込み)

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
import pandas as pd
import statsmodels.api as sm
from statsmodels.formula.api import ols
from statsmodels.stats.multicomp import pairwise_tukeyhsd

# ── この抜粋だけで動くように、結果変数 y と群 region を持つ表を用意する ──
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
df['y'] = df['A1303'] / df['A1101'] * 100          # 高齢化率(%) を結果変数に
df['region'] = pd.qcut(df['A1101'], 3, labels=['小', '中', '大'])  # 人口 3 区分を群に

# 数式に C(...) と書くとカテゴリ扱いになるが、このページでは前の例で
# 変数 C を作っているため C() が上書きされてしまう。
# region は category 型なので、そのまま書けばカテゴリとして扱われる。
model = ols('y ~ region', data=df).fit()
print(sm.stats.anova_lm(model, typ=2))
print(pairwise_tukeyhsd(df['y'], df['region'], alpha=0.05))
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) sum_sq df F PR(>F) region 182.156447 2.0 12.127649 0.000064 Residual 330.438462 44.0 NaN NaN Multiple Comparison of Means - Tukey HSD, FWER=0.05 ==================================================== group1 group2 meandiff p-adj lower upper reject ---------------------------------------------------- 中 大 -2.5906 0.0308 -4.9795 -0.2018 True
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

③ pingouin(最も「使いやすい」現代的ライブラリ)

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
1
2
3
4
5
import pingouin as pg
# ANOVA + η² + 等分散検定が一発
print(pg.anova(data=df, dv='y', between='region', detailed=True))
print(pg.welch_anova(data=df, dv='y', between='region'))
print(pg.pairwise_tukey(data=df, dv='y', between='region'))
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) Source SS DF MS F p_unc np2 0 region 182.156447 2 91.078224 12.127649 0.000064 0.355361 1 Within 330.438462 44 7.509965 NaN NaN NaN Source ddof1 ddof2 F p_unc np2 0 region 2 28.132072 13.780355 0.000067 0.355361 A B mean_A mean_B diff se T p_tukey hedges 0
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

④ scikit-learn — feature selection としての ANOVA F値

scikit-learn の SelectKBest(score_func=f_classif) は内部でカテゴリ y に対する ANOVA F検定を行い、 F値が大きい特徴量を選びます。 分類問題の前処理で頻出。

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
import pandas as pd
from sklearn.feature_selection import SelectKBest, f_classif

# ── この抜粋だけで動くように、特徴量 X と目的 y を用意する ──
# ANOVA の F 値は「群ごとに平均が違う特徴量」を選ぶのに使える
_d = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_d = _d[_d['SSDSE-B-2026'] == 2023]
_num = _d.select_dtypes(include='number').dropna(axis=1)
# 値が 1 種類しかない列は分散が 0 で F 値を計算できないので、先に落とす
_num = _num.loc[:, _num.nunique() > 1]
X = _num.values
y = (_d['A1101'] > _d['A1101'].median()).astype(int).values   # 人口が中央値超か

selector = SelectKBest(score_func=f_classif, k=10)
X_new = selector.fit_transform(X, y)
print(f'選ばれた特徴量: {X_new.shape[1]} 本 / 全 {X.shape[1]} 本')
# F 値が大きい順に上位 10 本を見る
_top = pd.Series(selector.scores_, index=_num.columns).sort_values(ascending=False)
print(_top.head(10).round(2).to_string())
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) 選ばれた特徴量: 10 本 / 全 109 本 H1801 45.96 H2601 45.60 E2101 35.22 C3301 32.62 A130301 31.80 A420002 31.50 E3401 31.31 A1303 31.09 A4200 30.95 E3101 30.78
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

⑤ ノンパラメトリック代替:Kruskal-Wallis

🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
from scipy import stats

# ── この抜粋だけで動くように、3 群のデータを用意する ──
_k = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
_k = _k[_k['SSDSE-B-2026'] == 2023].copy()
_k['aging'] = _k['A1303'] / _k['A1101'] * 100
_k['規模'] = pd.qcut(_k['A1101'], 3, labels=['小', '中', '大'])
a = _k.loc[_k['規模'] == '小', 'aging'].values
b = _k.loc[_k['規模'] == '中', 'aging'].values
c = _k.loc[_k['規模'] == '大', 'aging'].values

H, p = stats.kruskal(a, b, c)  # 正規性を仮定しない
print(f'Kruskal-Wallis H = {H:.3f}, p = {p:.4f}')
# 事後検定は Dunn or Mann-Whitney + Bonferroni
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) Kruskal-Wallis H = 18.235, p = 0.0001
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

⚠️ 10. よくある落とし穴

落とし穴 対処
ペアワイズ t検定の連発必ず ANOVA + post-hoc を使う。
有意で終わるどの群間に差があるかを post-hoc で示す。 η² と CI を併記。
交互作用を見ない二元配置では交互作用プロットを必ず描く。
不均衡データに Type I SS不均衡なら Type II/III SS を使う。
反復測定を独立ANOVAで処理必ず subject を within-subject 因子に。
前提条件をスキップ残差プロット・Levene検定を行う。
名義尺度を量的に扱うC() で明示的にカテゴリ化。

🏋️ 11. 練習問題(SSDSE-B-2026)

Q1. 都道府県を都市規模 3 群(総人口 A1101 の3分位)に分け、 標準地価(住宅地、 C5401)に差があるかを ANOVA で検定し、 Tukey HSD で post-hoc 比較しなさい。
🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
import pandas as pd
from scipy import stats
from statsmodels.stats.multicomp import pairwise_tukeyhsd

df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023]  # 2023年の47都道府県
df['都市規模'] = pd.qcut(df['A1101'], q=3, labels=['小規模県', '中規模県', '大規模県'])

groups = [g['C5401'].values for _, g in df.groupby('都市規模')]
F, p = stats.f_oneway(*groups)
print(f'ANOVA: F={F:.2f}, p={p:.4f}')
print(pairwise_tukeyhsd(df['C5401'], df['都市規模']))
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) ANOVA: F=8.83, p=0.0006 Multiple Comparison of Means - Tukey HSD, FWER=0.05 =============================================================== group1 group2 meandiff p-adj lower upper reject --------------------------------------------------------------- 中規模県 大規模県 68125.4167 0.0039 19664.6159 116586.2174 True 中規模県 小規模県 -6893.3333 0.9366 -55354.1341 41567.4674
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。
Q2. 都市規模 × 高齢化レベル(中央値分割)の2元配置 ANOVA を実施し、 交互作用プロットを描きなさい。
🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# ── この抜粋だけで動くように、都市規模つきの表を作り直す ──
df = pd.read_csv('data/raw/SSDSE-B-2026.csv', encoding='cp932', skiprows=[1])
df = df[df['SSDSE-B-2026'] == 2023].copy()
df['都市規模'] = pd.qcut(df['A1101'], 3, labels=['小', '中', '大'])
df['C5401'] = pd.to_numeric(df['C5401'], errors='coerce')   # 標準地価(住宅地)

df['高齢化率'] = df['A1303'] / df['A1101'] * 100  # 高齢人口/総人口
df['高齢度'] = (df['高齢化率'] >= df['高齢化率'].median()).map({True:'高', False:'低'})
sns.pointplot(data=df, x='都市規模', y='C5401', hue='高齢度', dodge=True)
plt.title('交互作用プロット')
plt.show()
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 このブロックは標準出力には何も出さない
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。
Q3. 残差の正規性と等分散性をチェックし、 違反していれば Kruskal–Wallis に切り替えなさい。
🎯 解説: SSDSE-B-2026 の都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州)に分け、 3 群以上の平均差を分散分析(ANOVA)で検定する。 t 検定の多群拡張であり、 F 統計量で「群間分散/群内分散」を評価する。
1
2
3
print(stats.shapiro(df['C5401']))
print(stats.levene(*groups))
print(stats.kruskal(*groups))
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年) 都道府県 地域ブロック B4101 年平均気温(℃) 北海道 北海道 11.0 東京都 関東 17.6 大阪府 近畿 18.0 沖縄県 九州 23.8
📤 実行例(実測) ShapiroResult(statistic=np.float64(0.5436207351059051), pvalue=np.float64(7.168536442057768e-11)) LeveneResult(statistic=np.float64(6.784649490056729), pvalue=np.float64(0.0027024531804879645)) KruskalResult(statistic=np.float64(16.44963790112751), pvalue=np.float64(0.00026792085169614536))
💬 読み方: F 値が大きく p < 0.05 なら「少なくとも 1 組の群間に差がある」。 「どの群間で差があるか」は事後検定(Tukey HSD など)で特定する。 効果量 η² は 0.01/0.06/0.14 が小/中/大の目安。 等分散仮定が崩れる場合は Welch ANOVA を用いる。

📝 12. 報告フォーマット

❌ NG例

「ANOVA の結果、 有意でした。」

✅ OK例

「都市規模 3 群(小規模県・中規模県・大規模県、 総人口 A1101 の3分位、 各 n=15〜16)の標準地価(住宅地、 C5401、 円/m²)を一元配置 ANOVA で比較した結果、 主効果が有意であった (F(2, 44) = 8.83, p < .001, η² = .29 大効果)。 Tukey HSD による post-hoc では、 大規模県群が小規模県群より有意に高く (Mdiff = 75,019 円/m², 95% CI [27,346, 122,692], p = .001)、 中規模県群よりも有意に高かった (Mdiff = 68,125 円/m², 95% CI [19,665, 116,586], p = .004)。 中規模県群と小規模県群の差は有意ではなかった (p = .937)。 なお正規性・等分散性の検定では違反が示されたため(Shapiro p < .001、 Levene p = .003)、 Kruskal–Wallis 検定でも確認した(H = 16.45, p < .001、 結論は同じ)。」

⚠️ ANOVA の落とし穴(深掘り版・6件)

① 等分散性の仮定を確認しない

古典的 ANOVA は「各群の分散が等しい」と仮定しています。 群間でばらつきが大きく違うと、 F検定が歪んで p値が信用できなくなります。 必ず Levene検定 か Bartlett検定 で確認。 違反していたら Welch ANOVAscipy.stats.f_oneway ではなく scipy.stats.alexandergovern や Welch 版)か Kruskal-Wallis(ノンパラ版)を使う。 違反を無視すると Type I エラー率が名目 5% から 10-20% まで膨れることがあります。

② 「F検定が有意」だけで報告を終える

F検定は「どこかの群が違う」とだけ言うので、 どのペアが違うかは別途調べる必要があります。 必ず Tukey HSD、 Dunnett、 Bonferroni などの事後検定を実行し、 さらに 効果量(η², ω²)95% 信頼区間も併記。 「F(2,57)=4.2, p=0.02」だけで終わらせず、 「群A対B:差=12.3、 95%CI [3.1, 21.5]、 d=0.65」のような完全報告が査読基準。

③ 多重比較補正を忘れる

3群比較で全ペアを比べると 3 回検定するので、 Type I エラーが累積。 「3つ全部が独立に α=0.05」ならいずれか1つで偽陽性となる確率は約 14%。 Bonferroni(α/k で割る)か Tukey HSD(同時信頼区間)か FDR(Benjamini-Hochberg)で補正。 ANOVA の F検定が「家族別 α を守る」と思い込んで、 事後で補正しないのが一番危険なパターン。

④ 正規性を「正規性検定」だけで判断する

サンプル数が大きいと Shapiro-Wilk 等の正規性検定はほぼ必ず棄却される(ささいな偏りも検出)。 一方サンプルが小さいと検出力が低くてどんな分布も「正規」と判定。 つまり正規性検定はサンプル数に振り回されるので使い物にならない場面が多い。 代わりに Q-Q プロット、 ヒストグラム、 歪度・尖度を目視で確認。 また各群 n > 30 なら中心極限定理で F検定はかなり頑健なので、 過度な心配は不要。

⑤ 反復測定で球面性を無視する

同じ被験者を複数回測る(被験者内要因がある)場合、 「すべての時点ペアの差の分散が等しい」という球面性(sphericity)の仮定が必要。 違反すると F検定の自由度が間違って大きくなり、 p値が過小評価される。 Mauchly 検定で確認、 違反ならGreenhouse-GeisserHuynh-Feldtで自由度補正、 または混合効果モデル(lmer)に移行。

⑥ 順序のあるカテゴリを「単に群」として扱う

「軽症・中等症・重症」のように順序のあるカテゴリ間で y を比べる時、 普通の ANOVA だと「順序情報」を捨ててしまう。 順序付き群間の単調傾向を検出するならJonckheere-Terpstra 検定線形傾向検定(直交対比)を使う。 「平均が単調に増えるか」という具体的仮説を検証できる。 順序を無視した普通のANOVA より検出力が高くなる。

🗺 概念マップ

関連概念を視覚的に整理した概念マップ。

分散分析 (ANOVA) t検定 Welchの ANOVA Kruskal-Wallis Post-hoc 検定 (Tukey) 効果量(η²・ω²)

中心の ANOVA から左の 効果量 へは「F 比だけでなく η²=SS_between/SS_total で実務的意味を測る」線、 上の t 検定 へは「2 群限定の特殊形、 t²=F (df1=1)」線、 右上の Welch ANOVA へは「等分散仮定が崩れた場合の代替」線、 右下の Kruskal-Wallis へは「正規性が破れた場合のノンパラ代替」線、 下の Tukey HSD へは「全体差有意の後にどの群ペアが異なるかを FWER 制御で特定」線でつながる。 ANOVA の本質は「総分散を群間分散と群内分散に分解し、 F 比で群間の系統的差を検出する分散分解の枠組み」であり、 SSDSE-B-2026(2023 年)の 47 都道府県を 8 地方区分に分けたとき、 年平均気温の地方差で総分散の η²=0.71 を説明できるという形で実値が読める。

🔗 隣接手法への橋渡し

ANOVA は「3 群以上の平均差検定」を起点に、 分散分解という枠組みで多くの隣接手法と連結する。

SSDSE-B-2026(2023 年)で「47 都道府県を 8 地方区分に分け、 年平均気温の地方差を検定」する場合、 一元配置 ANOVA で F 比と $\eta^2=0.71$ を得て、 Tukey HSD で具体的にどの地方ペアが異なるかを特定する一連の流れが標準パイプライン。

🌳 手法選択フロー

ANOVA の選択は「因子数」「測定の独立性」「正規性・等分散性」の 3 軸で判定する。

  1. 因子は 1 つか複数か? 1 因子 (例: 8 地方区分) → 一元配置 ANOVA。 2 因子 (例: 地方 × 性別) → 二元配置 ANOVA で主効果 + 交互作用も検出。 3 以上 → 多元配置 ANOVA。
  2. 同一個体を繰り返し測定? Yes (例: 同じ県の 2014-2024 年データ) → 反復測定 ANOVA、 Mauchly 球面性検定が必要。 No → 通常 ANOVA。
  3. 仮定確認: Shapiro-Wilk で正規性 → 違反軽微なら ANOVA、 大幅違反なら Kruskal-Wallis。 Levene で等分散 → 違反なら Welch ANOVA。 SSDSE-B-2026 (n=47) は中規模で、 効果量 $\eta^2$<0.06 は検出力不足の可能性に注意。

有意 → 必ず Tukey HSD などの事後検定でどの群ペアが違うかを特定。 全体差有意 = 全ペア差ありではない点が ANOVA 解釈の鉄則。

🎨 直感をもう一歩 — 「分散の比」がなぜ平均差の検定になるのか

ANOVA を一言でいうと 「シグナル ÷ ノイズ」の比を作って、 その比が偶然では説明できないほど大きいかを見る手法です。 ここでいうシグナルは群平均どうしのばらつき(群間)、 ノイズは同じ群の中での個体差(群内)。 3 群以上の平均がすべて同じ(帰無仮説)なら、 群平均のばらつきも「たまたま群内のばらつきから生じた程度」に収まるはずで、 このとき $F = \text{MS}_\text{between}/\text{MS}_\text{within}$ は理論上 1 前後になります。 逆に本当に群差があると分子だけが膨らみ、 F は 1 を大きく超えます。

なぜ「平均の差」を見たいのに「分散」を計算するのか? ポイントは、 群平均の散らばりを 1 つのスカラー(群間平方和)に要約すると、 群がいくつあっても検定を 1 回で済ませられる点にあります。 これが「t 検定を 3 群以上へ拡張したもの」と言われる理由です。 3 群を t 検定で総当たり(A-B, A-C, B-C)すると 3 回、 4 群なら 6 回と検定が増え、 多重比較により偽陽性が累積します(3 回なら「どれか 1 つで誤検出」の確率が約 14%)。 ANOVA はまず「全体としてどこかに差があるか」を 1 回の F 検定でまとめて判定し、 第一種の過誤が膨らむのを防ぎます。

2 群だけのときは、 t 検定と ANOVA は完全に等価で $F = t^2$(分子の自由度 $df_1 = 1$)という関係が成り立ちます。 つまり ANOVA は t 検定の一般化であり、 t 検定は ANOVA の特殊ケース。 検定統計量が「差の大きさ ÷ ばらつき」という同じ設計思想でできていることが、 $F = t^2$ という等式にそのまま表れています。 F の分母($\text{MS}_\text{within}$)が「共通の物差し(ものさし)」の役割を果たし、 群内ばらつきが大きいほど同じ平均差でも F は小さく=差を検出しにくくなります。

⚠️ 実務で効く落とし穴チェック(重要)

ANOVA は「回せば必ず p 値が出る」手法ですが、 前提が崩れた p 値は数字が出るだけで意味を持ちません。 実務で踏みやすい罠を、 判定の順序で整理します。

落とし穴 何が起きるか 対処
① 正規性を確認しない残差が大きく歪むと p 値がずれる(特に小標本・強い歪み)残差の正規性Shapiro–Wilk・QQ プロットで確認。 大幅違反は Kruskal–Wallis
② 等分散性を仮定したまま群でばらつきが違うと第一種の過誤が名目 5% から 10〜20% に膨張Levene / Bartlett 検定で確認。 違反時は Welch ANOVA(等分散を仮定しない版)
③ 独立性の破れ同一個体の反復・空間/時間の相関で有効サンプルが水増しされ p が過小サンプリング設計を見直す。 反復測定 ANOVA や混合効果モデル
④ 有意で満足して終えるF の有意は「どこかに差」だけ。 どの群かは分からない事後検定(Tukey HSD 等)でペアを特定。 多重比較補正込みで
⑤ 効果量を書かない大標本では小さな差でも p<0.05 になり「実質的な大きさ」が伝わらない効果量 η²(または偏り補正の ω²)を必ず併記。 η² の目安 0.01/0.06/0.14=小/中/大
⑥ 外れ値・不均衡データ1 点の外れ値が群平均を動かす/群サイズが極端に違うと SS の分解がタイプ依存に箱ひげ図で外れ値を可視化。 不均衡時は Type II/III 平方和を選び、 頑健手法も検討
⑦ 一元と二元を混同2 因子あるのに一元で回すと交互作用を見落とす(交絡)因子が 2 つ以上なら二元配置 ANOVA で主効果+交互作用を分離
✅ 前提チェックの実測(SSDSE-B-2026, 2023年, 47都道府県/合計特殊出生率 A4103 を 8 地方で比較) Levene 等分散検定 : p = 0.933 → 等分散仮定は棄却されない(古典 ANOVA が使える) Kruskal–Wallis(ノンパラ版): H = 33.48, p = 2.2e-05 → ANOVA と同じく強い地方差を支持 → 正規 ANOVA・ノンパラ代替の双方で結論が一致し、 前提の心配が小さい良いケース

💡 前提チェックの結論が「古典 ANOVA・Welch・Kruskal–Wallis のどれでも同じ」なら結論は頑健です。 逆に手法で結論が割れるときこそ、 どの前提が崩れているかを見極める必要があります。

🚀 発展 — ANOVA ファミリーの地図

一元配置 ANOVA を起点に、 因子の数・測定の構造・仮定の崩れ方に応じて手法が枝分かれします。 「何が起きたらどこへ進むか」を一望できるように整理します。

発展手法 いつ使うか 要点
一元配置 ANOVA因子が 1 つ(例: 地方区分だけ)3 群以上の平均差を 1 回で検定。 本ページの基本形
二元配置 ANOVA因子が 2 つ(例: 地方 × 都市規模)2 つの主効果に加え交互作用(片方の効果が他方の水準で変わるか)を分離
多元配置 ANOVA因子が 3 つ以上高次の交互作用まで扱えるが解釈が急に難しくなる。 交互作用プロット必須
反復測定 ANOVA同一個体を繰り返し測定(例: 同じ県の複数年)個体差を分離。 球面性を Mauchly 検定で確認し、 崩れたら Greenhouse–Geisser 補正
混合効果モデル独立性が崩れる・欠測やネスト構造がある固定効果+変量効果。 反復測定 ANOVA の一般化で、 不均衡・欠測に強い
Welch ANOVA等分散が崩れている(Levene で有意)分母を群ごとの分散で重み付け。 等分散を仮定せずに平均差を検定
Kruskal–Wallis正規性が大きく崩れる・順序尺度一元配置 ANOVA のノンパラ版(順位に基づく)。 反復測定版は Friedman 検定
事後検定(Tukey HSD)F が有意でどのペアか特定したい全ペア比較を FWER 制御下で。 対照群との比較は Dunnett、 汎用は Bonferroni
効果量 η² / ω²常に(p 値と併記)η²=SS_between/SS_total。 ω² は η² の上振れを補正した推定量。 Cohen's f も併用可
線形回帰への一般化連続共変量も入れたい(ANCOVA)ANOVA=カテゴリ変数だけの回帰。 共変量を足せば ANCOVA、 さらに一般化で GLM

関連ページ: t 検定(2 群版・$F=t^2$)/ 各種 t 検定F 検定仮説検定p 値自由度効果量多重比較多重検定Kruskal–Wallisノンパラメトリック法正規性Shapiro–Wilk 検定。 (Welch ANOVA・Tukey HSD・二元配置/反復測定 ANOVA・混合効果モデルは本ページ内で解説)

🧮 追加の実測例 — 合計特殊出生率の「地方差」を一元配置 ANOVA で

SSDSE-B-2026(cp932・skiprows=[1]・2023 年・47 都道府県)の合計特殊出生率 A4103を、 都道府県を 8 地方ブロック(北海道/東北/関東/中部/近畿/中国/四国/九州沖縄)に分けて一元配置 ANOVA で比較した実測結果です(数値はすべて実データから計算)。

地方 県数 出生率 平均 標準偏差
北海道11.06
東北61.1650.067
関東71.1510.084
中部91.3210.066
近畿71.2570.092
中国51.3900.063
四国41.3430.046
九州沖縄81.4550.098
📤 一元配置 ANOVA の実測結果(合計特殊出生率 A4103・2023年) F(7, 39) = 13.34, p = 1.23e-08 SS_between = 0.576, SS_within = 0.240 η² = 0.705(総変動の約 71% を地方差で説明=Cohen 基準で「大」) Levene 等分散: p = 0.933(等分散仮定OK) / Kruskal–Wallis: H = 33.48, p = 2.2e-05 Tukey HSD(有意ペアの例): 九州沖縄 vs 関東 差 = 0.304, 九州沖縄 vs 東北 差 = 0.290 → 地方ブロック間で合計特殊出生率に有意差あり。 九州沖縄が高く関東・東北が低い構造

💬 読み方: F(7,39)=13.34 で p は 10⁻⁸ 台と非常に小さく、 「少なくとも 1 組の地方間で出生率が違う」と言えます。 ただし F の有意は全体の差にすぎないので、 Tukey HSD で「九州沖縄 vs 関東」「九州沖縄 vs 東北」といった具体的にどのペアかを特定します。 効果量 η²=0.71 は非常に大きく、 統計的にも実質的にも顕著な地方差です。 なお北海道は 1 県のみ(n=1)で群内分散が定義できないため、 平均差の寄与は評価できても分散の議論からは外れる点に注意(不均衡データの一例)。 等分散(Levene p=0.93)・ノンパラ(Kruskal–Wallis)の双方でも結論が揃うため、 前提の崩れによる誤りの心配は小さい実測例です。

🔖 🔖 キーワード索引(チップから該当箇所へジャンプ)

論文記事から各用語のリンクをクリックすると、 該当箇所が開きます:

なぜANOVA F分布 一元配置ANOVA 二元配置ANOVA 交互作用 反復測定ANOVA 平方和分解 群間平方和 群内平方和 前提条件 Post-hoc検定 Tukey HSD Bonferroni 効果量 (η²) ノンパラ代替

🔖 キーワード索引(深掘り版)

論文・記事に登場する用語のリンクで該当箇所へジャンプ:

🧮 SSDSE 実値計算 ⚠️ 落とし穴 6選 🐍 Python バリエーション 🔗 関連用語 一元配置 二元配置 球面性 η²(効果量) 事後検定(Tukey)