🐍 13. ライブラリ早見表
🐍 13. ライブラリ早見表
用途
関数
一元配置ANOVA scipy.stats.f_oneway
二元配置ANOVA statsmodels.formula.api.ols + anova_lm
反復測定ANOVA statsmodels.stats.anova.AnovaRM
Welch's ANOVA pingouin.welch_anova
Tukey HSD statsmodels.stats.multicomp.pairwise_tukeyhsd
Bonferroni statsmodels.stats.multitest.multipletests(method='bonferroni')
Kruskal–Wallis scipy.stats.kruskal
Friedman scipy.stats.friedmanchisquare
📜 14. ANOVA の歴史
1918 :R.A. Fisher が分散分析を提案
1925 :Fisher の Statistical Methods for Research Workers で体系化
1935 :Fisher の The Design of Experiments で実験計画法の基礎が確立
1949 :Tukey が HSD 検定を提案
1960年代 :心理学・農学・医学で標準ツールに
1990年代以降 :混合モデル・GLM が発展、 ANOVA は GLM の特殊ケースと位置づけられるように
💼 15. 実務応用
農学 :肥料種別 × 品種の収穫量比較(二元配置)
製造業 :工場 × ラインの不良率(多元配置)
医療 :薬剤 × 用量の効果(反復測定)
教育 :教授法 × 学年の成績
マーケティング :広告クリエイティブ 3 種以上の効果比較
公共政策 :地域 3 群以上の指標比較
📋 16. ANOVA 表の読み方
statsmodels の anova_lm が出力する表の各列:
列
意味
sum_sq 平方和 SS。 各要因の説明する変動
df 自由度。 K-1(要因)、 N-K(残差)
F F統計量 = MS要因 / MS残差
PR(>F) F値以上の値が出る確率(p値)
SS の3タイプ(不均衡データで違いが出る)
Type I (sequential) :モデルへの投入順に逐次計算。 不均衡では順序依存
Type II :他主効果を調整、 交互作用は除外。 不均衡時の一般的選択
Type III :すべての他項を調整。 SAS 既定。 解釈に注意
🔗 17. ANOVA と回帰の等価性
ANOVA は実は「カテゴリ変数(ダミー変数)だけの線形回帰 」と数学的に等価。 statsmodels では同じ ols で記述できる。
🎯 解説: 総人口 A1101 の 3 分位で 47 都道府県を 小・中・大 の都市規模 3 群に分け、住宅地の標準地価 C5401 を一元配置 ANOVA(anova_lm)で検定する。同じモデルをダミー変数回帰の summary としても表示し、両者の F・p が一致することを見る。
📥 入力例(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年・47 行)
都道府県 A1101(総人口) 都市規模 C5401 住宅地地価(円/m²)
鳥取県 537,000 小 19,000
沖縄県 1,468,000 中 68,100
北海道 5,092,000 大 23,600
東京都 14,086,000 大 404,400
(小 16 県・中 15 県・大 16 県)
📤 実行例(実測)
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: OLS Adj. R-squared: 0.254
Method: Least Squares F-statistic: 8.833
Date: Sat, 29 Aug 2026 Prob (F-statistic): 0.000596
Time: 10:14:32 Log-Likelihood: -578.65
No. Observations: 47 AIC: 1163.
Df Residuals: 44 BIC: 1169.
Df Model: 2
Covariance Type: nonrobust
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
Intercept 2.69e+04 1.39e+04 1.936 0.059 -1109.901 5.49e+04
都市規模[T.中] 6893.3333 2e+04 0.345 0.732 -3.34e+04 4.72e+04
都市規模[T.大] 7.502e+04 1.97e+04 3.817 0.000 3.54e+04 1.15e+05
==============================================================================
Omnibus: 68.717 Durbin-Watson: 1.678
Prob(Omnibus): 0.000 Jarque-Bera (JB): 795.605
Skew: 3.623 Prob(JB): 1.72e-173
Kurtosis: 21.809 Cond. No. 3.70
==============================================================================
Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
💬 読み方: anova_lm の F=8.833・PR(>F)=0.000596 は、OLS summary の F-statistic 8.833・Prob 0.000596 と同じ数字で、ANOVA がダミー回帰の合同検定であることがそのまま見える。係数では基準の「小」26,900 円/m² に対し「中」は +6,893(p=0.732)で差がなく、「大」だけが +75,020(p<0.001)と離れる。ただし Skew 3.62・Kurtosis 21.8 と残差が強く歪んでおり、東京都 404,400 円/m² の影響が大きいので、対数変換や順位検定での確認が要る。
p値・F値は完全に一致する。 ANOVA の「カテゴリの主効果」が、 回帰の「ダミー係数の合同検定」に対応している。
✅ 18. ANOVA 実施チェックリスト
□ サンプル数が各群で確認できているか? (極端な不均衡は要注意)
□ 残差の QQ プロットを描いたか?
□ Levene 検定で等分散性を確認したか?
□ F値・自由度・p値を報告したか?
□ η² または ω² を報告したか?
□ 有意なら post-hoc(Tukey 等)を実施したか?
□ 二元配置なら交互作用プロットを描いたか?
□ 反復測定なら球面性を確認したか?
□ 前提が崩れているとき、 適切な代替手法に切り替えたか?
❓ 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(最もシンプル)
🎯 解説: 総人口の 3 分位(小 16・中 15・大 16 県)ごとに高齢化率(A1303/A1101×100)を 1 群とし、scipy.stats.f_oneway で 3 群の平均差を検定する。
📥 入力例(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年・47 行)
都道府県 A1101(総人口) A1303(65歳以上) 高齢化率(%) 人口3区分
鳥取県 537,000 179,000 33.3 小
秋田県 914,000 357,000 39.1 小
沖縄県 1,468,000 350,000 23.8 中
東京都 14,086,000 3,205,000 22.8 大
📤 実行例(実測)
F=12.128, p=0.0001
💬 読み方: F=12.128、p=0.0001 で、人口規模の 3 群の高齢化率は等しいとは言えない。群平均は小 33.90%、中 31.73%、大 29.14% で、人口が少ない県ほど高齢化が進んでいる。どの群どうしが違うのかはこの 1 行では分からないので、次の Tukey HSD で確かめる。
② statsmodels(事後検定・効果量込み)
🎯 解説: 高齢化率 y と人口 3 区分 region を statsmodels の ols と anova_lm で分散分析表にし、pairwise_tukeyhsd で 3 ペアの事後比較を行う。
📋 コピー 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年・47 行)
都道府県 A1101(総人口) A1303(65歳以上) 高齢化率(%) 人口3区分
鳥取県 537,000 179,000 33.3 小
秋田県 914,000 357,000 39.1 小
沖縄県 1,468,000 350,000 23.8 中
東京都 14,086,000 3,205,000 22.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
中 小 2.1753 0.0808 -0.2135 4.5642 False
大 小 4.766 0.0 2.416 7.116 True
----------------------------------------------------
💬 読み方: 分散分析表の F=12.128(自由度 2 と 44)は f_oneway と同じ値。Tukey HSD で有意なのは 小と大の差 4.77 ポイント(p-adj≈0.0000)と 中と大の差 2.59 ポイント(p-adj=0.0308)で、小と中の差 2.18 ポイントは p-adj=0.0808 で有意に届かない。全体の F だけでは見えない「人口の多い県だけが低い」という形がここで分かる。
③ pingouin(最も「使いやすい」現代的ライブラリ)
🎯 解説: 同じ表(y=高齢化率、region=人口 3 区分)を pingouin に渡し、効果量 np2 付きの ANOVA、等分散を仮定しない Welch ANOVA、Hedges の g 付きの Tukey 比較を続けて出す。
📋 コピー 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年・47 行)
都道府県 A1101(総人口) A1303(65歳以上) 高齢化率(%) 人口3区分
鳥取県 537,000 179,000 33.3 小
秋田県 914,000 357,000 39.1 小
沖縄県 1,468,000 350,000 23.8 中
東京都 14,086,000 3,205,000 22.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 小 中 33.902603 31.727279 2.175324 0.984905 2.208665 0.080805 0.800138
1 小 大 33.902603 29.136630 4.765974 0.968889 4.919010 0.000037 1.820390
2 中 大 31.727279 29.136630 2.590649 0.984905 2.630355 0.030847 0.839142
💬 読み方: pg.anova の F=12.128・p=0.000064 は statsmodels と一致し、np2=0.355 で高齢化率の変動の約 36% が人口規模の群で説明される。Welch ANOVA は分母の自由度が 44 から 28.13 に減るが、F=13.78・p=0.000067 と結論は変わらず、等分散の仮定は結果を左右していない。pairwise_tukey の hedges は 小と大 1.82、中と大 0.84 で、p 値だけでなく差の大きさも比べられる。
④ scikit-learn — feature selection としての ANOVA F値
scikit-learn の SelectKBest(score_func=f_classif) は内部でカテゴリ y に対する ANOVA F検定を行い、 F値が大きい特徴量を選びます。 分類問題の前処理で頻出。
🎯 解説: 2023 年の 47 都道府県の数値列 109 本を特徴量 X、「総人口が中央値 154.9 万人を超えるか」を 2 値の y とし、SelectKBest(f_classif) で ANOVA の F 値が大きい 10 本を選ぶ。
📋 コピー 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年・47 行 × 数値列 109 本)
都道府県 A1101(総人口) H1801(着工新設持家数) E2101(小学校数) y
鳥取県 537,000 1,242 114 0
沖縄県 1,468,000 2,411 266 0
北海道 5,092,000 8,168 950 1
東京都 14,086,000 13,289 1,323 1
📤 実行例(実測)
選ばれた特徴量: 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
💬 読み方: 上位は H1801(着工新設持家数)F=45.96、H2601(持家床面積)45.60、E2101(小学校数)35.22 と、人口に比例して大きくなる「絶対数」の列ばかり。y 自体を人口の大小で作っているので当然の結果で、選ばれた 10 本は人口の代わりになる列を拾ったにすぎない。一方で総人口 A1101 そのものの F は 24.65(33 位)にとどまり、東京都 1,409 万人が「中央値超」群の群内分散を膨らませると F 値が下がることも分かる。
⑤ ノンパラメトリック代替:Kruskal-Wallis
🎯 解説: 人口 3 区分(小・中・大)ごとの高齢化率 3 群に、正規性を仮定しない Kruskal–Wallis 検定をかける。
📋 コピー 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年・47 行)
都道府県 A1101(総人口) A1303(65歳以上) 高齢化率(%) 人口3区分
鳥取県 537,000 179,000 33.3 小
秋田県 914,000 357,000 39.1 小
沖縄県 1,468,000 350,000 23.8 中
東京都 14,086,000 3,205,000 22.8 大
📤 実行例(実測)
Kruskal-Wallis H = 18.235, p = 0.0001
💬 読み方: H=18.235(自由度 2)、p=0.0001 で、順位に置き換えても 3 群の高齢化率の差ははっきり残る。一元配置 ANOVA の F=12.128 と同じ結論なので、この差は外れ値や分布の形に頼ったものではない。どの群が違うかは Dunn 検定などで追加確認する。
📚 章構成
📚 章構成
🤔 1. なぜ ANOVA なのか
3 群以上を比較するときに、 t検定を全ペア(A-B、 A-C、 B-C)に対して繰り返すと、 family-wise 第一種過誤率が膨らむ。
K = 3 群:t検定 3 回。 全体 α ≈ 0.14(5%設定でも)
K = 6 群:t検定 15 回。 全体 α ≈ 0.54
ANOVA は「すべての群の平均が等しい 」という一つの帰無仮説を 1 回の検定で評価する。
📈 2. F分布
独立な $\chi^2$ 確率変数の比:
$$F = \frac{U_1/d_1}{U_2/d_2}, \quad U_1\sim\chi^2_{d_1},\ U_2\sim\chi^2_{d_2}$$
記号読み: $F$ は「エフ統計量」、 $d_1, d_2$ は分子・分母自由度。 ANOVA では分子=群間自由度、 分母=群内自由度。
🎯 解説: 自由度 (2,30)・(5,30)・(10,30) の F 分布の確率密度を scipy.stats.f.pdf で重ねて描き、分子の自由度で分布の形が変わる様子を見る。
📋 コピー import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
x = np . linspace ( 0 , 5 , 500 )
for df1 , df2 in [( 2 , 30 ), ( 5 , 30 ), ( 10 , 30 )]:
plt . plot ( x , stats . f . pdf ( x , df1 , df2 ), label = f 'F( { df1 } , { df2 } )' )
plt . title ( 'F分布' )
plt . legend (); plt . show ()
📥 入力例: データの読み込みは無い。x = 0〜5 を 500 等分した格子と、3 組の自由度 (d1, d2) だけを使う。
📤 このブロックは標準出力には何も出さない
💬 読み方: 標準出力は無く、図だけが出る。F(2,30) は 0 付近が最も高い右下がりの形、F(5,30) と F(10,30) は 1 の手前に山を持つ形になる。上側 5% 点は F(2,30)=3.32、F(5,30)=2.53、F(10,30)=2.16 と、分子の自由度(群数−1)が大きいほど小さい F で有意になるので、F 値は自由度と組にして読む。
🎯 3. 一元配置ANOVA
モデル
$$y_{ij} = \mu + \tau_i + \varepsilon_{ij}, \quad \varepsilon_{ij}\sim N(0, \sigma^2)$$
記号読み: $y_{ij}$ は「ワイ・サブ・アイ・ジェイ」、 群 $i$ の $j$ 番目の観測。 $\tau_i$ は群 $i$ の効果(「タウ・サブ・アイ」)。
3.1 平方和分解
$$\underbrace{\sum_{i,j}(y_{ij} - \bar{y}_{..})^2}_{SS_{total}} = \underbrace{\sum_{i}n_i(\bar{y}_{i.} - \bar{y}_{..})^2}_{SS_{between}} + \underbrace{\sum_{i,j}(y_{ij} - \bar{y}_{i.})^2}_{SS_{within}}$$
3.2 検定統計量
$$F = \frac{SS_{between}/(K-1)}{SS_{within}/(N-K)} = \frac{MS_{between}}{MS_{within}}$$
$F$ は群内変動に対する群間変動の比。 大きいほど群差あり。
3.3 実値で計算
3 群、 各群 3 サンプル:A=[2,3,4]、 B=[5,6,7]、 C=[8,9,10]
各群平均: 3, 6, 9、 全体平均: 6
$SS_{between} = 3(3-6)^2 + 3(6-6)^2 + 3(9-6)^2 = 27 + 0 + 27 = 54$
$SS_{within} = (2-3)^2+(3-3)^2+(4-3)^2 + ⋯ = 2 + 2 + 2 = 6$
$F = (54/2)/(6/6) = 27/1 = 27.0$ → 強く有意
🎯 解説: 3.3 の手計算を実データで回す。総人口 3 分位の都市規模 3 群で住宅地地価 C5401 を f_oneway にかける。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12 import pandas as pd
import numpy as np
from scipy import stats
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df = df [ df [ 'SSDSE-B-2026' ] == 2023 ] # 2023年の47都道府県
# 都道府県を「都市規模」3群に分割(総人口 A1101 の3分位)。C5401=標準地価(住宅地)
df [ '都市規模' ] = pd . qcut ( df [ 'A1101' ], q = 3 , labels = [ '小規模県' , '中規模県' , '大規模県' ])
groups = [ g [ 'C5401' ] . values for _ , g in df . groupby ( '都市規模' )]
f_stat , p_value = stats . f_oneway ( * groups )
print ( f 'F = { f_stat : .3f } , p = { p_value : .4f } ' )
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年・47 行)
都道府県 A1101(総人口) 都市規模 C5401 住宅地地価(円/m²)
鳥取県 537,000 小 19,000
沖縄県 1,468,000 中 68,100
北海道 5,092,000 大 23,600
東京都 14,086,000 大 404,400
(小 16 県・中 15 県・大 16 県)
📤 実行例(実測)
F = 8.833, p = 0.0006
💬 読み方: F=8.833、p=0.0006 は練習問題 Q1 と同じ計算。自由度は 2 と 44 で、F(2,44) の上側 5% 点 3.21 を大きく超える。手計算の例(F=27.0)と違い、実データでは群内のばらつきが大きいため F は 1 桁にとどまる。
🧩 4. 二元配置ANOVA
2 つの要因 A, B(と交互作用)の影響を同時に評価。
モデル
$$y_{ijk} = \mu + \alpha_i + \beta_j + (\alpha\beta)_{ij} + \varepsilon_{ijk}$$
記号読み: $\alpha_i$ は要因A・水準 $i$ の主効果、 $\beta_j$ は要因B・水準 $j$ の主効果、 $(\alpha\beta)_{ij}$ は交互作用効果。
4.1 交互作用とは
要因A の効果が要因B の水準で異なる現象。 「都市規模」と「地域(東日本/西日本)」を要因にしたとき、 都市規模の効果が地域で違うなら交互作用あり。
🎯 解説: 都市規模(人口 3 分位)と地域(北海道〜愛知の 23 都道県を東日本、残り 24 府県を西日本)の 2 要因で、住宅地地価 C5401 の交互作用つき二元配置 ANOVA(Type II)を行う。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 import statsmodels.api as sm
from statsmodels.formula.api import ols
# 都市規模 × 地域の2元配置
df [ '地域' ] = ( df [ 'Prefecture' ] . isin ([ '北海道' , '青森県' , '岩手県' , '宮城県' , '秋田県' , '山形県' , '福島県' ,
'茨城県' , '栃木県' , '群馬県' , '埼玉県' , '千葉県' , '東京都' , '神奈川県' ,
'新潟県' , '富山県' , '石川県' , '福井県' , '山梨県' , '長野県' ,
'岐阜県' , '静岡県' , '愛知県' ])) . map ({ True : '東日本' , False : '西日本' })
# 前のブロックで C という変数(ndarray)を作っているため、数式中の C() が
# それに隠されてしまう。列を category 型にして C() を使わない書き方にする。
df [ '都市規模' ] = df [ '都市規模' ] . astype ( 'category' )
df [ '地域' ] = df [ '地域' ] . astype ( 'category' )
model = ols ( 'C5401 ~ 都市規模 + 地域 + 都市規模:地域' , data = df ) . fit ()
anova_table = sm . stats . anova_lm ( model , typ = 2 )
print ( anova_table )
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年・47 行)
都道府県 都市規模 地域 C5401 住宅地地価(円/m²)
北海道 大 東日本 23,600
東京都 大 東日本 404,400
大阪府 大 西日本 155,200
鳥取県 小 西日本 19,000
📤 実行例(実測)
sum_sq df F PR(>F)
都市規模 5.125183e+10 2.0 7.744810 0.001402
地域 4.591174e+07 1.0 0.013876 0.906805
都市規模:地域 2.777119e+08 2.0 0.041966 0.958944
Residual 1.356602e+11 41.0 NaN NaN
💬 読み方: 都市規模の主効果は F=7.74、p=0.0014 で有意だが、地域(p=0.907)と交互作用(p=0.959)は効いていない。住宅地の地価は東西ではなく人口規模で分かれ、「都市規模の効果が東西で違う」証拠も無い。一元配置の F=8.83 より下がったのは、地域を調整した都市規模の平方和が 5.46e10 から 5.13e10 に減り、残差の自由度も 44 から 41 に減ったため。
🔁 5. 反復測定ANOVA
同じ個体に対して複数条件・複数時点で測定。 個人差をモデル外に出すことで検出力が上がる。
🎯 解説: 47 都道府県を「個体」、2021・2022・2023 年度を「反復測定の時点」とし、消費支出(二人以上の世帯、L3221)の年度差を AnovaRM で検定する。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12
13
14 from statsmodels.stats.anova import AnovaRM
# 同じ 47 都道府県を 2021・2022・2023 年度の 3 時点で測った long format
# (消費支出 L3221 の実測値。都道府県 = 個体、年度 = 反復測定の要因)
_all = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
long = _all [ _all [ 'SSDSE-B-2026' ] . isin ([ 2021 , 2022 , 2023 ])]
long = pd . DataFrame ({
'subject' : long [ 'Prefecture' ],
'time' : long [ 'SSDSE-B-2026' ],
'value' : pd . to_numeric ( long [ 'L3221' ], errors = 'coerce' ),
})
print ( long . groupby ( 'time' )[ 'value' ] . mean () . round ( 0 ))
res = AnovaRM ( data = long , depvar = 'value' , subject = 'subject' , within = [ 'time' ]) . fit ()
print ( res )
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2021〜2023年)を long format にしたもの
subject time value(L3221 消費支出, 円)
北海道 2021 268,396
北海道 2022 277,737
北海道 2023 296,888
東京都 2021 322,785
…(47 都道府県 × 3 年度 = 141 行)
📤 実行例(実測)
time
2021 281003.0
2022 289630.0
2023 295856.0
Name: value, dtype: float64
Anova
==================================
F Value Num DF Den DF Pr > F
----------------------------------
time 20.2027 2.0000 92.0000 0.0000
==================================
💬 読み方: 年度平均は 281,003 → 289,630 → 295,856 円と上がり、F=20.20(自由度 2 と 92)、p<0.0001 で年度の効果は有意。同じ 141 行を独立な 3 群として一元配置 ANOVA にかけると F=5.22、p=0.0065 にとどまるので、県ごとの水準差(東京都と北海道の約 4〜5 万円の差など)を誤差から外したことで検出力が上がっている。
🔍 6. Post-hoc 検定
ANOVA で有意になっても「どの群間に差があるか」は分からない。 Post-hoc 検定で特定する。
6.1 Tukey HSD(最も広く使われる)
全ペア比較を行い、 family-wise α を制御。
🎯 解説: 6.1 の Tukey HSD を、都市規模 3 群の住宅地地価 C5401 に pairwise_tukeyhsd で当てる(全ペアで family-wise α=0.05)。
📋 コピー from statsmodels.stats.multicomp import pairwise_tukeyhsd
result = pairwise_tukeyhsd ( endog = df [ 'C5401' ],
groups = df [ '都市規模' ],
alpha = 0.05 )
print ( result )
📥 入力例: data/raw/SSDSE-B-2026.csv(cp932・skiprows=[1]・2023年・47 行)
都道府県 A1101(総人口) 都市規模 C5401 住宅地地価(円/m²)
鳥取県 537,000 小 19,000
沖縄県 1,468,000 中 68,100
北海道 5,092,000 大 23,600
東京都 14,086,000 大 404,400
(小 16 県・中 15 県・大 16 県)
📤 実行例(実測)
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 False
大規模県 小規模県 -75018.75 0.0012 -122691.5177 -27345.9823 True
---------------------------------------------------------------
💬 読み方: 有意なのは大規模県を含む 2 ペア(中規模県との差 68,125 円/m²、小規模県との差 75,019 円/m²)。中規模県と小規模県の差 6,893 円/m² は信頼区間 −55,354〜41,567 が 0 を含むので reject=False。区間の半幅が約 48,000 円/m² と広いのは、大規模県群の大きなばらつきが共通の誤差分散を押し上げているため。
6.2 Bonferroni 補正
全ペアの p値 × ペア数。 シンプルだが保守的。
6.3 Dunnett(対照群との比較)
1 群を「対照」とし、 他群をすべて対照と比較する。 K-1 個の比較のみ。
ANOVA は「推測統計・検定」グループの主要教材で、 t 検定の多群拡張として位置づけられます。 SSDSE-B-2026 を題材にした地域ブロック間比較の実装例から始めるのが最短ルート。
同カテゴリの他用語と組み合わせると、 「2 群 → 多群 → 多変量 → 階層モデル」へと拡張する学習パスが見えてきます。
📚 Round 18 — 分散分析 (ANOVA) 完全攻略補足
ANOVA 一元配置 二元配置 F 統計量 群間/群内 多重比較 SSDSE-B-2026 区間推定 事前計画 post-hoc
🔬 数式を言葉で読み解く(拡張 narration)
🔬 数式を言葉で読み解く(narration): A1101 → 総人口(人)。 群分けした各群の規模を測る基本量です。A4101 → 出生数(人)。 群間で平均差を比べる応答変数の一例。B4101 → 年平均気温(℃)。 地域ブロック間で明確に差が出る典型例。L3221 → 消費支出(二人以上の世帯、円)。 群差が出にくい対照例。μ → 全国平均。 比較基準 として用います。α → 有意水準。 第一種の誤り 許容率(分散分析 (ANOVA) に関する判断で重要)。p → p 値。 H₀ の下でデータがどれだけ稀かを示す。
📐 補足の数式と読み解き 基本量の関係を、 記号 → 意味で整理します。 任意の比率は
$$\text{比率} = \frac{\text{分子}}{\text{分母}} \times 100\quad\text{単位: }\%$$
記号 → 意味:
分子 → SSDSE では A1301(15歳未満人口) 分母 → SSDSE では A1101(総人口) ×100 → 単位を「割合(小数)」から「%」に変える(例: 年少人口割合) 平均と分散は
$$\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i,\quad s^2 = \frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})^2$$
t 統計量・効果量は
$$t = \frac{\bar{x}_1 - \bar{x}_2}{\sqrt{s_1^2/n_1 + s_2^2/n_2}},\quad d = \frac{\bar{x}_1 - \bar{x}_2}{s_{\text{pooled}}}$$
🧮 実値で計算してみる — SSDSE-B-2026 47 都道府県
SSDSE-B-2026 の都道府県データから 分散分析 (ANOVA) の文脈で代表値を読み取ります。 各列の記号 → 意味を確認し、 平均・中央値・四分位を併記する習慣を身につけましょう。
都道府県 総人口 A1101(人) 出生数 A4101(人) 年平均気温 B4101(℃) 記号 → 意味 北海道 5,092,000 24,430 11.0 最北 → 全国最低の年平均気温 秋田県 914,000 3,611 13.7 東北の寒冷県 → 出生数も全国最小級 東京都 14,086,000 86,348 17.6 巨大分母 → 平均を引き上げる外れ値の典型 大阪府 8,763,000 55,292 18.0 大都市圏の中位 → 比較基準として有用 沖縄県 1,468,000 12,549 23.8 最南 → 全国最高の年平均気温
🐍 Python 実装 — Round 18 拡張
一元配置 ANOVA — 地域 3 群(東日本/西日本/沖縄)の年平均気温 🎯 SSDSE-B-2026(都道府県データ)を 分散分析 (ANOVA) の文脈で読み解く実値計算例。 各セルの記号 → 意味(A1101 → 総人口, B4101 → 年平均気温)を確認しながら手元の Jupyter で実行できます。
📥 入力例(SSDSE-B-2026 の 2023 年・47 都道府県から 3 行)
都道府県 B4101(年平均気温)
北海道 11.0
東京都 17.6
沖縄県 23.8
…(全 47 行)
📋 コピー import pandas as pd
from scipy import stats
df = pd . read_csv ( 'data/raw/SSDSE-B-2026.csv' , encoding = 'cp932' , skiprows = [ 1 ])
df = df [ df [ 'SSDSE-B-2026' ] == 2023 ] . copy () # 2023年の47都道府県
df [ 'temp' ] = df [ 'B4101' ] # B4101 = 年平均気温(℃)
okinawa = df [ df [ 'Prefecture' ] == '沖縄県' ][ 'temp' ]
west = df [ df [ 'Prefecture' ] . isin ([ '大阪府' , '京都府' , '兵庫県' , '広島県' , '福岡県' ])][ 'temp' ]
east = df [ df [ 'Prefecture' ] . isin ([ '東京都' , '神奈川県' , '千葉県' , '埼玉県' , '北海道' ])][ 'temp' ]
F , p = stats . f_oneway ( okinawa , west , east )
print ( f 'F= { F : .3f } , p= { p : .4f } ' )
📥 入力: data/raw/SSDSE-B-2026.csv(47 都道府県 × 主要統計列)。 出力例は数値・p 値・統計量で、 解釈には「実値で計算してみる → 仮説検定 → 効果量 → 結論」の流れを推奨します。
📤 実行例(実測)
F=4.917, p=0.0405
💬 F=4.917、p=0.0405 で、5% 水準ではぎりぎり「3 群の平均気温に差がある」となる。群平均は沖縄 23.8℃、西日本 5 府県 17.88℃、東日本 5 都道県 16.38℃ だが、東日本の平均は北海道の 11.0℃ 1 県に大きく引き下げられている(残り 4 都県は 17.2〜18.1℃)。沖縄群は 1 県しかなく群内分散を持たないので、この F 値は群の選び方しだいで簡単に動くと考えておく。
Tukey HSD で多重比較 🎯 SSDSE-B-2026(都道府県データ)を 分散分析 (ANOVA) の文脈で読み解く実値計算例。 各セルの記号 → 意味(A1101 → 総人口, B4101 → 年平均気温)を確認しながら手元の Jupyter で実行できます。
📋 コピー from statsmodels.stats.multicomp import pairwise_tukeyhsd
import numpy as np
vals = np . concatenate ([ okinawa , west , east ])
grp = [ '沖縄' ] * len ( okinawa ) + [ '西日本' ] * len ( west ) + [ '東日本' ] * len ( east )
print ( pairwise_tukeyhsd ( vals , grp ))
📥 入力: data/raw/SSDSE-B-2026.csv(47 都道府県 × 主要統計列)。 出力例は数値・p 値・統計量で、 解釈には「実値で計算してみる → 仮説検定 → 効果量 → 結論」の流れを推奨します。
📤 実行例(実測)
Multiple Comparison of Means - Tukey HSD, FWER=0.05
=====================================================
group1 group2 meandiff p-adj lower upper reject
-----------------------------------------------------
東日本 沖縄 7.42 0.0336 0.6451 14.1949 True
東日本 西日本 1.5 0.5428 -2.4115 5.4115 False
沖縄 西日本 -5.92 0.085 -12.6949 0.8549 False
-----------------------------------------------------
💬 3 ペアのうち有意なのは東日本と沖縄の差 7.42℃(p-adj=0.0336)だけで、西日本と沖縄の差 5.92℃ は信頼区間が −12.69〜0.85 と 0 をまたぐため p-adj=0.085 で棄却されない。差の大きさはあまり変わらないのに判定が分かれたのは、東日本の群内ばらつき(北海道の 11.0℃)が誤差の見積もりを大きくしているため。区間幅が ±6.8℃ と広いのも、沖縄が n=1 であることの表れ。
二元配置 ANOVA — 地域 × 都市規模 🎯 SSDSE-B-2026(都道府県データ)を 分散分析 (ANOVA) の文脈で読み解く実値計算例。 各セルの記号 → 意味(A1101 → 総人口, B4101 → 年平均気温)を確認しながら手元の Jupyter で実行できます。
📋 コピー 1
2
3
4
5
6
7
8
9
10
11
12 import statsmodels.formula.api as smf
import statsmodels.api as sm
from patsy.builtins import C # 上のブロックで C という配列を作ったので明示的に読み込む
# 47 都道府県すべてを 東日本(北海道〜中部, コード 01〜23)/ 西日本(三重〜沖縄, 24〜47)に分け、
# 総人口 200 万人で 大/小 に分ける → 4 つのセルすべてに県が入る
df [ 'code' ] = df [ 'Code' ] . str [ 1 : 3 ] . astype ( int )
df [ 'region' ] = ( df [ 'code' ] <= 23 ) . map ({ True : '東' , False : '西' })
df [ 'size' ] = ( df [ 'A1101' ] > 2000000 ) . map ({ True : '大' , False : '小' })
print ( df . groupby ([ 'region' , 'size' ])[ 'temp' ] . agg ([ 'count' , 'mean' ]) . round ( 2 ))
model = smf . ols ( 'temp ~ C(region) + C(size) + C(region):C(size)' , data = df ) . fit ()
print ( sm . stats . anova_lm ( model , typ = 2 ))
📥 入力: data/raw/SSDSE-B-2026.csv(47 都道府県 × 主要統計列)。 出力例は数値・p 値・統計量で、 解釈には「実値で計算してみる → 仮説検定 → 効果量 → 結論」の流れを推奨します。
📤 実行例(実測)
count mean
region size
東 大 11 16.15
小 12 15.27
西 大 5 17.88
小 19 17.86
sum_sq df F PR(>F)
C(region) 57.578474 1.0 18.561992 0.000094
C(size) 2.719430 1.0 0.876682 0.354341
C(region):C(size) 1.722297 1.0 0.555229 0.460242
Residual 133.384089 43.0 NaN NaN
💬 4 セルの県数は 東・大 11、東・小 12、西・大 5、西・小 19。地域の主効果は F=18.56、p=0.000094 と強く、東日本平均 15〜16℃ 台に対して西日本は大小とも約 17.9℃ である。人口規模の主効果(p=0.354)と交互作用(p=0.460)は有意でなく、「大都市ほど暖かい」ように見えた差は地域の違いでほぼ説明される。セルの人数が 5〜19 と不均衡なので、ここでは Type II の平方和を使っている。
効果量 η² の計算 🎯 SSDSE-B-2026(都道府県データ)を 分散分析 (ANOVA) の文脈で読み解く実値計算例。 各セルの記号 → 意味(A1101 → 総人口, B4101 → 年平均気温)を確認しながら手元の Jupyter で実行できます。
📋 コピー import numpy as np
# 3 群(沖縄・西日本 5 府県・東日本 5 都道県)の 11 件だけで分散を分解する
groups = [ okinawa , west , east ]
sub = np . concatenate ( groups )
grand = sub . mean ()
ss_between = sum ( len ( g ) * ( g . mean () - grand ) ** 2 for g in groups )
ss_total = (( sub - grand ) ** 2 ) . sum ()
print ( f 'n= { len ( sub ) } , SS_between= { ss_between : .2f } , SS_total= { ss_total : .2f } ' )
print ( f 'η²= { ss_between / ss_total : .3f } ' )
📥 入力: data/raw/SSDSE-B-2026.csv(47 都道府県 × 主要統計列)。 出力例は数値・p 値・統計量で、 解釈には「実値で計算してみる → 仮説検定 → 効果量 → 結論」の流れを推奨します。
📤 実行例(実測)
n=11, SS_between=46.07, SS_total=83.55
η²=0.551
💬 比較した 11 都道府県だけで分解すると、全平方和 83.55 のうち群間平方和が 46.07 を占め、η²=0.551 になる。これは直前の F=4.917(自由度 2 と 8)から η² = 2F/(2F+8) で求めた値とも一致する。η² は 0.14 以上で「大」と呼ぶ目安を大きく超えるが、11 件・沖縄 1 県という小さな比較なので、効果量も区間を付けずに断定しない方がよい。
❓ よくある質問 (FAQ)
3 群以上を比べるのに t 検定を繰り返すと何が困る? α が膨らみます。 α=0.05 で 3 ペアなら 1−(0.95)^3 ≈ 0.143。 ANOVA + 多重比較補正で全体 α を制御します。
有意な ANOVA の後、 どのペアで差があるかは? Tukey HSD, Bonferroni, Holm などの post-hoc 検定で各ペアを比較します。
一元配置と二元配置の違いは? 要因が 1 つなら一元、 2 要因かつ交互作用も評価するなら二元。 例: 「地域 × 業種」で売上を分析する場合は二元。
不等分散・正規性違反では? Welch's ANOVA や Kruskal-Wallis(ノンパラ)を使います。
ANOVA の効果量は? η²(イータ二乗)や ω². 全変動に対する群間変動の割合を表します。
⚠️ 拡張版 落とし穴チェックリスト 分母を確認しない罠 : 比率や率の意味は分母で決まります。 SSDSE で「per 1000」と「per 100」を取り違えると桁違いになります。外れ値の影響 : 東京都が平均値を引き上げる効果は実際に大きく、 中央値との乖離を必ず併記しましょう。因果と相関の混同 : 高齢化率と消費支出(L3221)が相関しても、 因果は別問題。 第三変数(産業構造・気候)の介在を疑います。選択バイアス : 「都市部のサンプルだけ」では地方の構造が見えません。 47 都道府県すべてを観察しましょう。多重比較 : 47 都道府県を一斉比較すると α=0.05 でも約 2.35 件は偶然有意。 Bonferroni 等の補正が必須です。時点ずれ : SSDSE-B-2026 と 国勢調査 2020 では基準時点が異なります。 同期した比較が必要。分散分析 (ANOVA) 特有の文脈ずれ : 教育用に正規化したサンプルと現場データの落差。 単位・桁・カテゴリを揃える前処理が肝心。
🔗 関連用語(前提・並列・発展)— Round 18 補強
分散分析 (ANOVA) を中心に、 前提概念・並列分野・発展手法へリンクします。
📚 関連グループ教材
グループ教材から 分散分析 (ANOVA) の文脈に直結する論文・ハンズオンを辿れます。
🕰 歴史的背景と現代 分散分析 (ANOVA) は古典統計と社会データの交差点で発達してきました。 19 世紀末から 20 世紀初頭にかけて Pearson, Fisher, Neyman などが基礎を整え、 戦後の公的統計整備により実務応用が広がりました。
2010 年代以降は、 「再現性危機」「ビッグデータ」「AI 倫理」の三つの波が 分散分析 (ANOVA) に新しい意味を与えました。 単に p<0.05 を出すのではなく、 効果量・信頼区間・事前登録・データシートが必須となっています。
日本では総務省統計局・国立社会保障人口問題研究所・経済産業省 RESAS などが公的統計を整備し、 教育用に SSDSE が無償公開されました。 本ページもこの枠組みで 分散分析 (ANOVA) を扱います。
📚 参考リンク 総務省統計局 e-Stat https://www.e-stat.go.jp/ SSDSE 公開ページ https://www.nstac.go.jp/use/literacy/ssdse/ scipy.stats 公式ドキュメント https://docs.scipy.org/doc/scipy/reference/stats.html statsmodels 公式 https://www.statsmodels.org/ JIS Q 38507 / ISO/IEC 22989(AI 用語) OECD Principles on AI(2019)
🌐 関連手法・派生(広域マップ)
同じカテゴリの手法、 上位概念、 派生分野へのリンクを補強します。
📊 補講 R279: ANOVA を「分散の天秤」で読み解く
分散分析 (ANOVA) は「3 群以上の平均値が全部等しいか」を検定する手法ですが、 内部処理は 「群間分散 (between)」と「群内分散 (within)」の比 (F 値)」 を測ります。 F 値が 1 に近ければ「群間ばらつきと群内ばらつきは同程度=差は誤差レベル」、 F 値が 1 より大幅に大きければ「群間ばらつきが群内ばらつきを上回る=群間に系統差あり」と判断します。 本補講では、 SSDSE-B-2026(2023 年)の都道府県データを「8 地方区分」に分けて年平均気温 (B4101) の差を一元配置 ANOVA で評価し、 F 値・p 値・効果量 η²・事後検定 (Tukey HSD) の読み方を 3 枚の図と 1 表で整理します。
▶ 3 枚の図で ANOVA の判定構造を直感する
図 R279-1: F 分布と観測 F 値の位置関係。 F 値は常に正で、 平均がほぼ 1 の右に裾を引く分布。 棄却域は右側のみ (片側) で、 自由度 (df1, df2) によって形が変わる。 図は 47 都道府県を 8 地方区分に分けたときの F(7, 39) で、 α=0.05 の棄却限界は 2.26。 観測 F 値は年平均気温 13.38(棄却域のはるか右)、 出生数 2.72(棄却域内)、 消費支出 2.18(棄却限界のわずかに左)で、 下の早見表の判定と一致する。
F 分布は 右に裾を引く非対称分布 で、 t 分布や正規分布と違って片側のみで判定します (両側の概念がない)。 自由度は (df1=群数-1, df2=全標本-群数) の二段構えで、 df1 が大きいほど分布の中心は 1 に近寄り、 df2 が大きいほど裾が薄くなります。 47 都道府県を 8 地方区分に分けた場合、 df1=7, df2=39 となり、 棄却限界は α=0.05 で F=2.25 付近です。 観測 F 値が 2.25 を超えれば「8 地方間で年平均気温に差あり」と判定します。
図 R279-2: t 分布 (両側) と F 分布 (右側のみ) の比較。 ANOVA は分散の比を扱うため、 必然的に右側のみの分布になる。 2 群比較なら t² = F の関係が成立。 図は近畿 7 府県(平均 17.36℃)と九州 8 県(平均 19.04℃)の年平均気温で、 等分散を仮定した t 検定の t = 2.114 と、 同じ 2 群の ANOVA の F = 4.467 = 2.114² が対応し、 両側 p と右側 p はどちらも 0.0545 になる。
数学的には、 2 群の t 検定と一元配置 ANOVA は完全に等価で、 t² = F の関係が成立します (df1=1 の F 検定)。 例えば等分散を仮定した 2 群の t 検定(Student の t 検定)で t=2.0 なら、 同じデータの ANOVA で F=4.0 が得られます(分散を別々に推定する Welch の t 検定では t² = F は成り立ちません)。 3 群以上を扱う際に、 全ペアに t 検定をかけると 多重比較問題 (n 個のペアで偽陽性率が高まる) が発生するため、 まず ANOVA で「全体として差があるか」を一括検定し、 有意なら Tukey HSD 等の事後検定で「どのペアに差があるか」を特定する 2 段階方式が標準です。
図 R279-3: ANOVA の p 値も「H0 (全群が等しい) が真の世界で、 観測 F 値以上の極端な結果が出る確率」。 t 検定と同じ頻度論的解釈。 図は F(7, 39) の右裾の面積で、 出生数(F = 2.718)は p = 0.0214、 消費支出(F = 2.178)は p = 0.0576。
ANOVA の p 値も t 検定と同じ頻度論的解釈で、 「H0 が真の世界で観測 F 値以上の極端な結果が偶然得られる確率」を意味します。 「H0 が正しい確率」 ではない点に注意。 ANOVA で p < 0.05 が出ても、 それは「どこかに差がある」という大まかな結論で、 「どの群同士に差があるか」 は別途、 事後検定 (Tukey HSD / Bonferroni / Scheffé / Games-Howell) で特定します。
▶ 8 地方区分の F 値・p 値・効果量早見表 (SSDSE-B-2026)
指標 F 値 df1 df2 p 値 η² (効果量) 判定 (α=0.05)
年平均気温 (B4101) 13.383 7 39 1.2e-08 0.706 (大) ✓ 有意
出生数 (A4101) 2.718 7 39 0.0214 0.328 (大) ✓ 有意
消費支出 (L3221) 2.178 7 39 0.0576 0.281 (大) ✗ 非有意
η² (eta squared) は ANOVA の効果量指標で、 「群間で説明できる分散の割合」を意味します。 Cohen (1988) の目安では η²=0.01 が小、 0.06 が中、 0.14 が大。 年平均気温 η²=0.71 は「総分散の約 71% が地方区分で説明できる」という強い結果で、 47 都道府県の年平均気温は地方区分との関連が極めて強いことを示します。 消費支出は p=0.058 で(α=0.05 では)非有意ですが、 η²=0.28 と「大きめの効果量」が出ており、 サンプルを拡張すれば有意域に入る可能性があります。
▶ ANOVA + Tukey HSD を Python で一気通貫
このコードでやること : SSDSE-B-2026(2023 年)の 47 都道府県を 8 地方区分に分け、 年平均気温 (B4101) の一元配置 ANOVA を scipy.stats.f_oneway で実行し、 統計的に有意なら statsmodels の Tukey HSD で「どの地方間に差があるか」を特定する。
📥 入力データ (地方区分追加後の抜粋):
Prefecture B4101(年平均気温℃) region
北海道 11.0 北海道
東京都 17.6 関東
沖縄県 23.8 九州
... (47 行 × 8 地方)
📋 コピー 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 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 ] . copy () # 2023年の47都道府県。B4101=年平均気温
# 8 地方区分の割当
region_map = {
'北海道' : [ '北海道' ], '東北' : [ '青森県' , '岩手県' , '宮城県' , '秋田県' , '山形県' , '福島県' ],
'関東' : [ '茨城県' , '栃木県' , '群馬県' , '埼玉県' , '千葉県' , '東京都' , '神奈川県' ],
'中部' : [ '新潟県' , '富山県' , '石川県' , '福井県' , '山梨県' , '長野県' , '岐阜県' , '静岡県' , '愛知県' ],
'近畿' : [ '三重県' , '滋賀県' , '京都府' , '大阪府' , '兵庫県' , '奈良県' , '和歌山県' ],
'中国' : [ '鳥取県' , '島根県' , '岡山県' , '広島県' , '山口県' ],
'四国' : [ '徳島県' , '香川県' , '愛媛県' , '高知県' ],
'九州' : [ '福岡県' , '佐賀県' , '長崎県' , '熊本県' , '大分県' , '宮崎県' , '鹿児島県' , '沖縄県' ],
}
pref_to_region = { p : r for r , lst in region_map . items () for p in lst }
df [ 'region' ] = df [ 'Prefecture' ] . map ( pref_to_region )
# ANOVA (一元配置)
groups = [ g [ 'B4101' ] . values for _ , g in df . groupby ( 'region' )]
F , p = stats . f_oneway ( * groups )
# 効果量 η²
ss_between = sum ( len ( g ) * ( g . mean () - df [ 'B4101' ] . mean ()) ** 2 for g in groups )
ss_total = (( df [ 'B4101' ] - df [ 'B4101' ] . mean ()) ** 2 ) . sum ()
eta2 = ss_between / ss_total
print ( f 'ANOVA F= { F : .3f } p= { p : .5f } η²= { eta2 : .3f } ' )
# 事後検定 (Tukey HSD)
if p < 0.05 :
tukey = pairwise_tukeyhsd ( df [ 'B4101' ], df [ 'region' ], alpha = 0.05 )
print ( tukey . summary ())
📤 実行すると次の出力が得られる:
ANOVA F=13.383 p=0.00000 η²=0.706
Multiple Comparison of Means - Tukey HSD, FWER=0.05
=====================================================
group1 group2 meandiff p-adj lower upper reject
-----------------------------------------------------
中国 中部 -0.4222 0.9982 -2.5753 1.7309 False
中国 九州 2.2375 0.0439 0.0369 4.4381 True
中国 北海道 -5.8 0.002 -10.0286 -1.5714 True
中国 四国 0.925 0.9427 -1.6645 3.5145 False
中国 東北 -3.0167 0.0042 -5.3541 -0.6792 True
中国 近畿 0.5571 0.9928 -1.7032 2.8174 False
中国 関東 0.3286 0.9997 -1.9317 2.5889 False
中部 九州 2.6597 0.0013 0.784 4.5354 True
中部 北海道 -5.3778 0.0031 -9.4468 -1.3088 True
中部 四国 1.3472 0.5857 -0.9725 3.6669 False
中部 東北 -2.5944 0.0048 -4.6289 -0.5599 True
中部 近畿 0.9794 0.7407 -0.966 2.9247 False
中部 関東 0.7508 0.9161 -1.1946 2.6961 False
九州 北海道 -8.0375 0.0 -12.1319 -3.9431 True
九州 四国 -1.3125 0.6384 -3.6764 1.0514 False
九州 東北 -5.2542 0.0 -7.3389 -3.1694 True
九州 近畿 -1.6804 0.1555 -3.6782 0.3175 False
九州 関東 -1.9089 0.0701 -3.9068 0.0889 False
北海道 四国 6.725 0.0003 2.4092 11.0408 True
北海道 東北 2.7833 0.4106 -1.3862 6.9528 False
北海道 近畿 6.3571 0.0004 2.2304 10.4839 True
北海道 関東 6.1286 0.0007 2.0019 10.2553 True
四国 東北 -3.9417 0.0003 -6.4334 -1.4499 True
四国 近畿 -0.3679 0.9997 -2.7874 2.0516 False
四国 関東 -0.5964 0.9928 -3.0159 1.8231 False
東北 近畿 3.5738 0.0001 1.4262 5.7214 True
東北 関東 3.3452 0.0003 1.1976 5.4929 True
近畿 関東 -0.2286 1.0 -2.2919 1.8348 False
-----------------------------------------------------
💬 結果の読み方 : F=13.383, p=1.2e-08, η²=0.706 で 「8 地方間に年平均気温の差あり」 と結論できる。 Tukey HSD で 九州・四国 (温暖) vs 東北・北海道 (寒冷) の差が個別に有意。 九州と四国の差は非有意 (p=0.64) で、 地理的に近い温暖地域どうしは差が小さい。 ANOVA の単独 p 値だけでなく、 効果量 η²=0.71 が「実務的にも大きな効果」を裏付けている点が重要。
▶ ANOVA の前提と代替手法 — 早見表
前提 確認方法 崩れた場合の代替
各群の正規性 Shapiro-Wilk / Q-Q プロット Kruskal-Wallis 検定 (順位ベースのノンパラメトリック)
群間の等分散性 Levene / Bartlett 検定 Welch ANOVA (oneway.test in R)、 Games-Howell 事後検定
観測値の独立性 研究設計の確認 反復測定 ANOVA / 混合モデル (Linear Mixed Model)
サンプル数の均衡 各群の n 確認 Type III SS を採用、 不均衡な設計でも頑健
▶ 理解度チェック (R279)
設問 期待される回答
Q1. ANOVA で p<0.05 が出たら何が分かる? 「どこかに差がある」だけで、 どのペア間に差があるかは Tukey HSD 等の事後検定で特定する必要がある。
Q2. F = t² の関係はいつ成立する? 2 群比較 (df1=1) のとき、 等分散仮定の Student t 検定と一元配置 ANOVA が完全に等価。 t²=F が成立する。
Q3. ANOVA の代わりに t 検定を全ペアに使うと何が問題? 多重比較問題。 群数 k のとき k(k-1)/2 個のペアがあり、 各 α=0.05 だと偽陽性率が 1-0.95^(k(k-1)/2) と急増する。
Q4. η² と η²_p (partial η²) の違いは? η² は総分散に対する説明割合、 η²_p は誤差分散と要因分散の和に対する割合。 二元配置以上で要因の純粋効果を見たい時は η²_p。
Q5. ANOVA で正規性が崩れた時の代替は? Kruskal-Wallis 検定 (順位ベース)。 scipy.stats.kruskal。 事後検定は Dunn 検定 (scikit_posthocs.posthoc_dunn)。
本補講で扱った要素は 仮説検定 、 t 検定 、 F 検定 、 p 値 、 効果量 、 多重比較 、 正規性 、 Kruskal-Wallis 、 回帰分析 の各ページと連結し、 群間比較の現場運用に直結する判断材料となる。
▶ 補講補足: ANOVA を「設計型」と「事後型」に分けて運用する
ANOVA は一見「3 群以上の平均値の差検定」 という単機能ツールに見えますが、 実務では 研究設計の階層 (一元・二元・反復測定・混合) によって解釈が大きく変わります。 ここでは ANOVA を (1) 一元配置から二元配置・反復測定への発展、 (2) 固定効果と変量効果の区別、 (3) 球面性 (sphericity) 仮定と Greenhouse-Geisser 補正、 (4) ANOVA から線形回帰・線形混合モデル (LMM) への一般化、 (5) Bayesian ANOVA との対比、 の 5 観点で整理し、 実装と報告書のテンプレートまで提示します。
(1) 一元配置から二元配置・反復測定への発展 : 一元配置 ANOVA は「1 つの要因 (例: 8 地方区分) で平均差を検定」 する最も単純な設計。 二元配置 ANOVA は「2 つの要因 (例: 地方区分 × 性別) + 交互作用」 を同時検定し、 主効果と交互作用を分離できます。 反復測定 ANOVA は「同じ対象を複数回測定 (例: 2010/2015/2020 年の都道府県人口)」 で、 個体差をモデルに組み込むことで検出力が大きく上がります。 SSDSE-B-2026 を使う場合、 8 地方 × 4 経済指標で二元配置、 各都道府県を 5 年間追跡データに拡張すれば反復測定設計が可能になります。 二元配置以上では 交互作用効果 の解釈が中心で、 「地方による高齢化率の差が、 男女で異なる」 のような複合的な現象を統計的に検証できます。
(2) 固定効果と変量効果の区別 : ANOVA の要因には「固定効果」 と「変量効果」 の区別があります。 固定効果 (fixed effect) は「研究者が選んだ全ての水準を検討対象とする」 もので、 例: 8 地方区分。 変量効果 (random effect) は「母集団から無作為抽出された水準で、 母集団全体への一般化が目的」 もので、 例: 47 都道府県 (47 個の都道府県は「全国の母集団」 から抽出した標本と見なす場合)。 固定効果の F 検定は MS_要因 / MS_誤差 ですが、 変量効果の F 検定は MS_要因 / MS_交互作用 など分母が変わります。 統計ソフトのデフォルトは固定効果で、 変量効果指定は明示的に行う必要があります。 statsmodels.formula.api では mixedlm 関数で変量効果を組み込めます。
(3) 球面性 (sphericity) 仮定と Greenhouse-Geisser 補正 : 反復測定 ANOVA には「球面性 (sphericity)」 という追加仮定があり、 これは「水準ペア間の差の分散が全て等しい」 ことを要求します。 SSDSE-B の 5 年間追跡なら、 (2010-2015) と (2015-2020) と (2010-2020) の差分散が等しいということです。 Mauchly 検定で球面性を確認し、 違反していれば Greenhouse-Geisser 補正 (ε で自由度を調整) や Huynh-Feldt 補正を適用します。 補正により p 値は大きくなる方向に動き、 偽陽性を防ぎます。 ε=1 で補正なし、 ε=1/(水準数-1) で最大補正。 報告書には「球面性検定 W=0.85, p=0.12 (違反なし) → 補正なし採用」 のように記述します。
(4) ANOVA から線形回帰・線形混合モデル (LMM) への一般化 : ANOVA は実は 線形回帰の特殊形 です。 「8 地方区分」 を 7 個のダミー変数で表現し OLS 回帰を実行すれば、 一元配置 ANOVA と完全に等価な結果 (F 値・p 値・η²) が得られます。 この視点を持つと、 ANCOVA (共分散分析)、 多変量 ANOVA (MANOVA)、 線形混合モデル (LMM)、 一般化線形混合モデル (GLMM) まで自然に拡張できます。 例えば「8 地方区分の高齢化率差を、 総人口 (A1101、 連続変数) を共変量として調整」 したいなら ANCOVA、 「同じ都道府県を 5 年間追跡 + 都道府県ごとの個体差をモデル化」 したいなら LMM が適切です。 statsmodels.formula.api ols('y ~ C(region)', data=df).fit() の anova_lm 出力は、 線形モデルから ANOVA 表を生成する古典的アプローチです。
(5) Bayesian ANOVA との対比 : 頻度論的 ANOVA は「H0 が真の世界での確率」 を扱いますが、 Bayesian ANOVA は「データを観察した後の H0 と H1 の事後確率の比 (Bayes Factor)」 を扱います。 Bayes Factor BF10 > 3 は「H1 を支持する moderate evidence」、 BF10 > 10 は「strong evidence」、 BF10 < 1/3 は「H0 を支持」 という具体的解釈が可能で、 「非有意」 と「H0 支持」 を区別できる利点があります。 頻度論 ANOVA で p=0.20 が出たとき、 「効果がない」 のか「データ不足で検出できなかった」 のかは判別できませんが、 Bayesian ANOVA なら BF01=5 (H0 を支持する moderate evidence) と明示できます。 Python では bayes-anova ライブラリや、 PyMC で手動構築が可能です。
ANOVA 報告書テンプレート : 学術論文と実務レポート共通の最低限報告事項。 (A) 設計タイプ (一元 / 二元 / 反復測定)、 (B) 要因と水準 (固定 / 変量の区別)、 (C) サンプルサイズ (各群)、 (D) 前提検定の結果 (正規性: Shapiro-Wilk、 等分散性: Levene、 球面性: Mauchly)、 (E) F 値、 自由度 (df1, df2)、 p 値、 (F) 効果量 (η², partial η², ω²)、 (G) 事後検定の結果 (Tukey HSD / Bonferroni)、 (H) サブグループ別の記述統計 (平均・SD・n)。 文章例: 「SSDSE-B-2026(2023 年)の 47 都道府県を 8 地方区分に分け、 年平均気温 (B4101) の一元配置 ANOVA を実行した結果、 F(7, 39) = 13.38, p < 0.001, η² = 0.71 で有意差を確認。 Tukey HSD により、 九州 (平均 19.0℃) は東北 (13.8℃, p<0.001)、 北海道 (11.0℃, p<0.001) と比べて有意に高温だった。 等分散性は Levene 検定、 正規性は群ごとの Shapiro-Wilk で確認する。」 — このように 前提検定 + 主検定 + 事後検定 + 効果量 の四点セットを記述すれば、 査読での主要指摘は事前に防げます。
最後に、 ANOVA は「群間比較」 と「分散分解」 の二つの側面を持つ手法であり、 「群間でどこが違うか」 (Tukey HSD)、 「総分散のどれだけを要因で説明できるか」 (η²)、 「他の要因で調整すべきか」 (ANCOVA)、 「個体差を分離すべきか」 (LMM) と、 質問の性質に応じて拡張が可能です。 47 都道府県を扱う SSDSE-B-2026 のような中規模データでは、 一元配置 ANOVA で全体差を確認し、 二元配置で交互作用を探り、 LMM で経年変化を追うという段階的アプローチが効果的です。 t 検定 から ANOVA へ、 ANOVA から線形混合モデルへの拡張は、 統計学習の自然な階梯であり、 一段ずつ理解を深めていくことで、 複雑な現実データを解釈する力が身につきます。
関連: 仮説検定 / t 検定 / F 検定 / 効果量 / 多重比較 / 回帰分析 / Kruskal-Wallis / 正規性 / サンプルサイズ / 信頼区間
▶ 補講補足 VII: ANOVA と隣接分野 — 因果推論・ベイズ・機械学習との接続
ANOVA は単独の手法ではなく、 因果推論・ベイズ統計・機械学習との接続を意識すると活用の幅が広がります。 因果推論との接続: ANOVA は「群間の平均差」 を検定しますが、 ランダム化実験では「処置効果」 として解釈可、 観察データでは交絡補正が必要です。 ANCOVA (共分散分析) はこの補正の一形態。 ベイジアン ANOVA (Rouder et al. 2012) は BayesFactor パッケージで実装可能で、 「H0 を支持する evidence」 を明示でき、 「非有意」 と「H0 支持」 の区別が可能です。 機械学習との接続: SHAP 値や Permutation Importance による特徴量重要度の分解は、 「現代版分散分解」 として ANOVA の発想を継承しています。 これらの隣接分野との接続を意識することで、 ANOVA から始まる統計的判断のスキルが、 線形混合モデル・因果推論・機械学習解釈手法へと自然に発展していきます。 SSDSE-B-2026 の都道府県データで一元配置 ANOVA を実装する経験から、 二元配置・反復測定・ベイジアン・GLMM・SHAP 値解釈へと段階的に学ぶ姿勢が、 統計的判断の力を高める道筋です。
▶ 補講補足 VI: ANOVA の社会的役割と倫理的留意
ANOVA は医学・心理学・教育学・経済学・農学などの研究分野で広く使われ、 社会的判断の根拠となっています。 例えば「複数の治療法の効果比較」 「複数の教育プログラムの成果比較」 「複数の政策の効果検証」 などで ANOVA が標準ツールです。 この社会的役割を考えると、 ANOVA の運用にも倫理的留意点があります。 (1) 「全体差」 と「個別差」 の混同 : ANOVA で全体差が有意でも、 全ペアに差があるわけではありません。 「ANOVA で有意 → 政策 A・B・C すべてに違いあり」 と早合点して全政策を変えるのは誤りで、 Tukey HSD で「A と B の差のみ有意」 等を確認すべきです。 (2) 「複数比較の隠蔽」 : 100 個の指標を ANOVA で比較し、 偶然有意な指標だけ報告するのは多重比較問題を隠す不誠実な運用です。 検定した指標の総数を明示し、 補正後の判定を報告すべきです。 (3) 「効果量の無視」 : ANOVA で p<0.05 が出ても、 η²<0.06 (小効果量) なら実務的意味は限定的です。 「統計的有意 ≠ 実務的に重要」 という区別を社会的判断の場面で常に意識すべきです。 (4) 「群間で標本サイズが大幅に違う」 状況 : 不均衡な設計では Type III SS を採用し、 各群のサンプル数を明示すべきです。 「都市圏 1000 例、 地方圏 50 例」 のような不均衡で「地方圏は効果が見えない」 と結論するのは、 検出力不足が原因かもしれません。 (5) 「因子分けが事後選択」 の罠 : ANOVA の因子は事前に定義すべきで、 結果を見てから因子を切り替えるのは解析の自由度問題を引き起こします。 「8 地方区分」 を「東日本/西日本の 2 区分」 や「都市圏/非都市圏の 2 区分」 と結果を見てから切り替えるのは禁忌です。 これらの倫理的留意を意識することで、 ANOVA を社会的に責任ある形で運用できます。 ANOVA は「群間比較の技術」 であると同時に、 「社会的判断を支える統計的枠組み」 として、 その透明性と再現性を保つ運用が現代では強く求められています。
▶ 補講補足 V: 教材設計の視点 — ANOVA を教えるベストプラクティス
ANOVA を学生・新人データサイエンティストに教える際の効果的アプローチを整理します。 (1) 「t 検定 の拡張」 ではなく「分散分解」 として導入 : t 検定 の拡張として教えると、 「ANOVA は 3 群以上の差検定」 という機械的理解で止まりがちです。 「総分散 = 群間分散 + 群内分散」 という分散分解の発想から教えると、 線形回帰の R²、 機械学習の SHAP 値分解、 ベイジアン階層モデルなどへの自然な接続が見えます。 (2) 「実データで分散分解を体感」 : SSDSE-B-2026 の 47 都道府県を 8 地方区分に分け、 「8 地方間の差で総分散の何 % が説明できるか?」 を計算させると、 年平均気温で η²=0.71 という具体数で「地方差の影響力」 が伝わります。 (3) 「F 比の直感的解釈」 : F = MS_group / MS_within を「群間ばらつきが群内ばらつきの何倍か」 と説明すると、 F=1 → 同程度、 F>>1 → 群間差あり、 という判定が直感的に理解できます。 (4) 「事後検定の必要性」 を強調 : 「ANOVA で全体差を見て、 Tukey HSD で個別差を特定する」 という 2 段階の論理を最初から教えることで、 「ANOVA で有意 → 全ペアに差あり」 という誤解を防げます。 (5) 「線形モデルの一族」 として位置づけ : ANOVA を「線形回帰の特殊形」 として教えると、 ANCOVA・LMM・GLMM・機械学習への拡張が自然に見えます。 statsmodels の formula API で ols('y ~ C(region)', data=df).fit() の出力が ANOVA 表になることを示すと、 線形モデルの統一的視点が定着します。 これらの教育設計を意識することで、 ANOVA を「群間比較の道具」 から「線形モデルの一族の中核概念」 へと進化させることができます。
▶ 補講補足 III: 実務での落とし穴と対処の追加事例
SSDSE-B-2026 で ANOVA を実行する際に遭遇する追加の典型的落とし穴を整理します。 (1) 「群数 = 7」 と「水準数 = 8」 の表現混乱 : 8 地方区分の ANOVA は「因子の水準数 = 8」 で、 df1 = 水準数 - 1 = 7。 「群数」 と呼ぶか「水準数」 と呼ぶかは慣習で違いがあり、 報告書には「8 群一元配置 ANOVA、 df=(7, 39)」 のように明示すべきです。 (2) 「主効果が有意 → 交互作用無視」 の罠 : 二元配置 ANOVA で、 主効果が有意なら交互作用を無視して解釈する人が多いですが、 交互作用が有意な場合は主効果単独の解釈が誤解を招きます。 「地方による高齢化率の差が、 男女で異なる」 のような交互作用があれば、 「男性は地方差あり、 女性は地方差なし」 のように分けて報告すべきです。 (3) 「ANOVA で非有意 → 効果なし」 の早合点 : 検出力不足で非有意な可能性があり、 効果量 η² が中程度 (0.06-0.14) なら「サンプル増強で有意化の可能性あり」 と注釈すべき。 SSDSE-B-2026 (n=47) は中規模で、 効果量 η²=0.10 程度の差は検出力 0.50 程度で見逃される可能性があります。 (4) 「等分散仮定違反 → 単に Welch で済ます」 の単純化 : 等分散仮定違反が中程度なら Welch ANOVA で対応可ですが、 違反が大きい場合や分布形状が大きく異なる場合は、 サブグループ別の分析やロバスト ANOVA (Trimmed ANOVA)、 Kruskal-Wallis などへの切替も検討すべきです。 (5) 「事後検定をすべての群ペアで実行」 の多重比較問題 : 8 地方なら 28 ペアあり、 各 α=0.05 だと偶然有意の期待値は 1.4 件。 Tukey HSD は FWER (Family-Wise Error Rate) を制御しますが、 報告には「FWER=0.05、 28 ペア」 のように補正の概念を明示すべきです。
これらの落とし穴を避けるための「ANOVA ベストプラクティス・チェックリスト 10 項目」: (1) 設計タイプ (一元 / 二元 / 反復) を明示、 (2) 固定効果と変量効果を区別、 (3) 各群の n を均衡させる (不均衡なら Type III SS)、 (4) 正規性を Shapiro-Wilk で群別に確認、 (5) 等分散性を Levene 検定で確認、 (6) 違反があれば Welch / Kruskal-Wallis に切替、 (7) 球面性 (反復測定の場合) を Mauchly 検定で確認、 (8) 効果量 η² / partial η² を計算、 (9) 事後検定 (Tukey HSD など) で個別差を特定、 (10) 業務 KPI への翻訳。 これら 10 項目を毎回確認することで、 ANOVA の運用品質は大きく向上し、 査読・社内レビューでの主要指摘は事前に防げます。 ANOVA は「群間比較」 と「分散分解」 を同時に扱う柔軟な枠組みで、 検定としてだけでなく、 「データの構造を理解する道具」 として運用することが現代的アプローチです。
▶ 補講補足 IV: ANOVA の歴史と現代的展開
ANOVA は 1918-1925 年にかけて Ronald A. Fisher が開発した手法で、 Rothamsted 農業試験場での「品種・肥料・土壌条件の効果を分離する実験設計」 が源流です。 Fisher は『Statistical Methods for Research Workers』 (1925) で ANOVA を体系化し、 1935 年の『The Design of Experiments』 で実験計画法 (Design of Experiments, DoE) の基礎を確立しました。 ANOVA の「F 比 (Fisher's F-ratio) 」 という名前は、 Fisher の頭文字に由来します (正確には George Snedecor が Fisher に敬意を表して命名)。 ANOVA は 100 年以上の歴史を持ちながら、 現代の医学・心理学・教育学・農学・品質管理で主力手法であり続けています。
Fisher の時代、 農業実験では「3 品種 × 4 肥料」 のような直交配置が普通で、 主効果と交互作用を分離する ANOVA の枠組みが革命的でした。 当時、 「品種だけを比較する単純な比較」 では「肥料の影響が混ざる」 「実験区画の場所差が混ざる」 という交絡問題があり、 ANOVA はそれを 分散分解 で解決しました。 「総分散 = 品種分散 + 肥料分散 + 交互作用分散 + 残差分散」 のように分解することで、 各要因の純粋な効果を抽出できます。 SSDSE-B-2026 の文脈で言えば、 「8 地方区分の高齢化率差を、 総人口 (A1101) や消費支出 (L3221) の影響を除いて分離する」 ような調整が ANCOVA (共分散分析) でも可能です。
現代的展開として、 (a) 一般化線形混合モデル (GLMM) は ANOVA を任意の応答変数 (連続・二値・カウント) と任意の効果構造 (固定・変量・階層) に拡張した枠組みで、 「47 都道府県を 8 地方にネストしつつ、 5 年間の経時測定を組み込む」 のような複雑な設計を扱えます。 lme4 (R)、 statsmodels.formula.api.mixedlm (Python) で実装可能。 (b) ベイジアン ANOVA (Rouder et al. 2012) は BayesFactor パッケージで簡単に実行でき、 「H0 を支持する evidence」 を明示できる強みがあります。 (c) 順序応答 ANOVA (順序ロジスティック回帰、 ALDEx2 など) は、 Likert スケール (1-5 の順序評価) のような順序データに対する ANOVA 代替として実装されています。 (d) 機械学習との融合 として、 SHAP 値による特徴量重要度分解は「現代版 ANOVA」 として位置づけ可能で、 非線形・高次元の応答に対しても要因の寄与を分解できます。
医療分野での ANOVA の活用例として、 (a) 臨床試験での「プラセボ群 + 既存薬群 + 新薬群」 の 3 群比較で、 一元配置 ANOVA + Tukey HSD は標準ツール、 (b) 経時測定での「投薬前・1 週後・4 週後・12 週後」 の比較は反復測定 ANOVA、 (c) 「投薬群 × 性別 × 年齢層」 の交互作用解析は三元配置 ANOVA、 (d) 個人差を考慮した「投薬効果の患者間変動」 は線形混合モデル、 のように、 ANOVA は医療統計の主力ツールとして今も発展しています。 経済学では、 (a) 都道府県別の経済指標の地方差検定、 (b) 業種別の収益率分析、 (c) 政策介入の効果検証 (DiD と ANOVA の組合せ)、 などで活用されます。 心理学では、 (a) 実験群間の認知テストスコア比較、 (b) 被験者内デザインの反復測定 ANOVA、 (c) 多因子設計の交互作用解析、 などが標準です。
統計教育における ANOVA の扱い方として、 一元配置 ANOVA を「t 検定 の拡張」 として導入することが多いですが、 これは 誤解を招く可能性 があります。 t 検定 は「2 群の平均差」 を測りますが、 ANOVA は「分散の分解」 という別概念を扱います。 t² = F の関係 (df1=1 のとき) は数学的等価性ですが、 概念的には異なる視点 (差検定 vs 分散分解) を持つことを理解させるべきです。 また、 ANOVA を多重 t 検定 の代替として教えると、 「ANOVA で全体差を見て、 Tukey HSD で個別差を特定する」 という 2 段階の論理が見えなくなります。 ANOVA の本質は「分散分解 → 要因の説明力を η² で定量化」 であり、 これは線形回帰の R² と等価な概念です。 統計教育では、 ANOVA を線形回帰の特殊形として教える「一般線形モデル (General Linear Model) 視点」 が、 後の機械学習への接続も含めて教育的価値が高いです。
最後に、 ANOVA は 100 年以上の歴史を持ちながら、 現代でも GLMM や ベイジアン ANOVA、 機械学習との融合で発展を続けている「生きた統計手法」 です。 単なる「3 群以上の平均差検定」 として暗記するのではなく、 (1) 分散分解という概念、 (2) 線形モデルの一族としての位置づけ、 (3) 実験計画法との連動、 (4) 効果量 η² による実務的解釈、 (5) 事後検定による個別差の特定、 をセットで理解することで、 ANOVA を現代的に使いこなせるようになります。 SSDSE-B-2026 の 47 都道府県データで一元配置 ANOVA を実装する経験を積みながら、 二元配置・反復測定・GLMM へと段階的に拡張していく姿勢が、 統計的判断の力を高める道筋です。 ANOVA は単独で完結する手法ではなく、 線形回帰・因果推論・機械学習へとつながる統計学の中核概念として位置づけることが、 質の高いデータ分析を実現する鍵です。
🧾 発表前の最終確認
分散分析を発表で使う時は、 群平均の差だけでなく、 群内ばらつき、事後比較、効果量、前提確認を合わせて示します。 p値だけで結論を急がず、 どの群がどの程度違うのかを図表で説明することが重要です。