分散分析と共分散分析:基礎からPython実装までわかりやすく解説
こんにちは、青の統計学です。
「分散分析(ANOVA)」と、そこからさらに一歩進んだ「共分散分析(ANCOVA)」について解説します。ビジネスシーンや研究、データ分析の現場でも活用範囲が広い手法であり、知っておくと有用です。
1. 分散分析(ANOVA)の概要
1-1. 分散分析とは
分散分析(ANOVA: Analysis of Variance) は、複数の群(例えば、3群以上)の平均値に有意な差があるかどうかを一度に検討するための手法です。一元分散分析(One-way ANOVA)と呼ばれるもっとも基本的なバージョンでは、以下の帰無仮説と対立仮説を考えます。
- 帰無仮説 ${H_0}$: すべての群の母平均は等しい
- 対立仮説 ${H_1}$: 少なくとも1つの群の母平均は他と異なる
3群以上の平均値を比較する場合、t検定を組み合わせて何度も実施すると、多重比較による危険率増大問題(Type I error の蓄積)が起こります。
ANOVAの利点
一回の検定で「どこかに差があるか」をまとめてチェックできる
1-2. F値とF分布
分散分析では、以下のように「群間の変動」と「群内の変動」の比を取ったF値を用います。このF値がF分布に従うことを利用し、p値を求めます。
$${F = \frac{\frac{\text{群間の平方和}}{\text{群間の自由度}}}{\frac{\text{群内の平方和}}{\text{群内の自由度}}} \quad \Longleftrightarrow \quad F \sim F(df_\text{between}, \; df_\text{within})}$$
- 群間の平方和 (SSB: Sum of Squares Between)
- 各群の平均と全体平均のずれによる変動を測ったもの。
- 群内の平方和 (SSW: Sum of Squares Within)
- 各群のデータとその群の平均のずれによる変動を測ったもの。
- 群間の自由度 ${df_\text{between} = k – 1}$
- 群の数(${k}$)から1を引いたもの。
- 群内の自由度 ${df_\text{within} = n – k}$
- 全データ数(${n}$)から群の数を引いたもの。
1-3. 分散分析のコード例(Python)
以下では、3群のテストスコアデータを用いて、一元分散分析を行う例を示します。
実際にPython環境で動かして確認してみてください。
import numpy as np
import pandas as pd
import scipy.stats as stats
# 3つの群のデータ(例: テスト点数)
group1 = [12, 15, 16, 18, 20] # 補習なし
group2 = [22, 24, 26, 28, 30] # A先生による補習
group3 = [32, 34, 36, 38, 40] # B先生による補習
# 一元分散分析を実施
f_value, p_value = stats.f_oneway(group1, group2, group3)
print("F値:", f_value)
print("p値:", p_value)
# 有意水準の設定
alpha = 0.05
if p_value < alpha:
print("帰無仮説を棄却し、対立仮説を採択(群間で差がある)。")
else:
print("帰無仮説を採択(群間で差がない)。")
実行結果の一例は以下の通りです。
F値: 50.34931506849327
p値: 1.4573895567680738e-06
帰無仮説を棄却し、対立仮説を採択。
この結果から、3群の平均値に統計学的に有意な差があることがわかります。しかし、どの群とどの群の間に差があるのかは、ANOVAだけではわかりません。
そこで必要なのが、多重比較(ポストホック検定)です。
2. 多重比較(ポストホック検定)
2-1. 多重比較が必要な理由
分散分析(ANOVA)で「3群以上の平均値に差があるか」を検定し、もし有意差が見つかったとしても、「どの群とどの群の間に差があるのか」は分かりません。そこで、ペアごとの平均値差を検定(t検定など)する必要があります。
ところが、比較するペアの数だけ t検定を繰り返すと、有意水準 (α) が何度も使用されることになり、第I種の過誤(本来差がないのに有意と判定する誤り)を犯すリスクが高まります。
このように、多重比較を繰り返すことによって生じるの問題を「多重比較問題」と呼びます。
対策としては、以下のような多重比較法を用います。
- Tukey HSD (Honestly Significant Difference)
- Bonferroni補正
- Dunnett検定 など
一個紹介します。
2-2. Tukey HSD テスト
ビジネスにおける例だと、マーケティングの現場で「異なる3種類の広告手法(A, B, C)を実施したときの、コンバージョン率(または売上)がどう違うか」を知りたい場合を考えます。ANOVA で「少なくとも1種類は他の広告手法と違う」ことを示したら、次は「どの広告手法とどの広告手法の間で差があるのか」を知る必要があります。
Tukey HSD テストを使えば、A-B, A-C, B-C のすべての比較を同時に統制しながら、どの広告手法が優位であるかを把握できます。
検定統計量の考え方
Tukey HSD テストでは、まず一元分散分析(ANOVA)の結果から得られる「群内平方和 (SSW) と群内自由度 (${df_{within}}$)」を用いて「群内平均平方(MSW)」を計算します。
そこから各群ペアの平均値差と、分散分析に基づいて推定した誤差とを比較して「どれだけ有意に離れているか」を評価します。具体的には、以下の統計量 ${Q}$(Studentized Range)を計算します。
$${Q = \frac{|\overline{X}_i – \overline{X}_j|}{\sqrt{\frac{MSW}{n}}}}$$
- ${\overline{X}_i, \overline{X}_j}$: 群 ${i, j}$ の標本平均
- ${MSW}$: 群内平均平方 (Mean Square Within)
- ${n}$: 各群のサンプルサイズ(すべての群が等サイズであると仮定)
Tukey HSD では、この ${Q}$ が「Studentized Range 分布」に従うことを利用します。ANOVA で使う F分布とは別の分布ですが、多重比較を行う目的で特化して定義された分布です。
2-2-2. 有意差判定の基準値
Tukey HSDテストでは、有意水準 ${\alpha}$、群数 ${k}$、群内自由度 ${df_{within}}$ をもとに「クリティカル値 ${q_{\alpha, k, df_{within}}}$」を求めます。
それに対し、各ペアに対して計算した上記の ${Q}$ を比較し、以下のように判定します。
$${Q > q_{\alpha, k, df_{within}} \quad \Longrightarrow \quad \text{有意差あり}}$$
$${Q \leq q_{\alpha, k, df_{within}} \quad \Longrightarrow \quad \text{有意差なし}}$$
実際の関数では、この計算と判定を自動で行い、結果として「平均値差」と「p値」と「有意かどうか (reject / fail to reject)」などを出力してくれます
2-2-3. pythonで実装
Pythonではstatsmodels
ライブラリが便利です。
from statsmodels.stats.multicomp import pairwise_tukeyhsd
data = np.concatenate([group1, group2, group3])
groups = (['group1'] * len(group1)
+ ['group2'] * len(group2)
+ ['group3'] * len(group3))
# Tukey HSDによる多重比較
tukey_result = pairwise_tukeyhsd(data, groups, alpha=0.05)
print(tukey_result)
出力結果としては、各群ペアについて「平均値の差」と「有意かどうか」が表示されます。
もし全ペアで有意差が検出されれば、「group1 < group2 < group3」のようにどれが優れている(高い平均を持つ)のかがわかります。
3. 効果量(エータ平方)とその解釈
統計的に有意差が見つかっただけでは、その差がどれほど大きいのかは把握できません。そこで注目したいのが効果量(effect size)です。一元分散分析においてしばしば用いられる指標にエータ平方 (${\eta^2}$) があります。
$${\eta^2 = \frac{\text{SSB}}{\text{SST}}}$$
- ${\text{SSB}}$: 群間の平方和
- ${\text{SST}}$: 全体(総和)の平方和(${\text{SSB} + \text{SSW}}$)
${\eta^2}$が${0}$に近いほど「ほぼ効果はなし」、1に近いほど「ほぼ群間の差で説明される」ことを意味します。
一般的には以下のような目安があります。
- 0.01未満: 効果がほとんどない
- 0.01~0.06: 小さい効果
- 0.06~0.14: 中程度の効果
- 0.14以上: 大きな効果
3-1. Pythonでのエータ平方算出例
# 群間平方和SSBを計算(厳密には各群の平均 - 全体平均の二乗和を足し合わせ)
ss_between = np.sum((np.mean(group1) - np.mean(np.concatenate([group1, group2, group3])))**2 * len(group1) +
(np.mean(group2) - np.mean(np.concatenate([group1, group2, group3])))**2 * len(group2) +
(np.mean(group3) - np.mean(np.concatenate([group1, group2, group3])))**2 * len(group3))
# 群内平方和SSWは各群の偏差平方和の合計
ss_within = np.sum((group1 - np.mean(group1))**2) \
+ np.sum((group2 - np.mean(group2))**2) \
+ np.sum((group3 - np.mean(group3))**2)
ss_total = ss_between + ss_within
eta_squared = ss_between / ss_total
print("η^2:", eta_squared)
上の例では大きめの効果量が得られるはずです
。例えば η^2: 0.63
といった値が出れば、「かなり強い効果があった」とみなせます。
4. 共分散分析(ANCOVA)とは
4-1. 分散分析の拡張としての共分散分析
共分散分析(ANCOVA: Analysis of Covariance) は、分散分析に共変量(Covariate: 従属変数に影響を与える可能性がある外部の連続変数)を加えたモデルです。単なる「ANOVA+回帰分析」といったイメージを持つとわかりやすいかもしれません。
たとえば、2つの指導法(グループ)の効果を比較する場合に「事前テストの点数」を共変量として入れることで、もともとの学力差を統計モデルに取り込み、指導法そのものの効果を正確に評価しようとする、というのがANCOVAの代表的な使い方です。
4-2. ANCOVAモデルの数式
共分散分析では、典型的に次のようなモデルを想定します。
$${y_{ij} = \mu + \alpha_i + \beta (x_{ij} – \bar{x}) + \varepsilon_{ij}}$$
- ${y_{ij}}$: ${i}$ 番目のグループに属する被験者 ${j}$ の従属変数(例: テストの点数)
- ${\mu}$: 全体平均
- ${\alpha_i}$: 各グループの効果
- ${\beta}$: 共変量の回帰係数
- ${x_{ij}}$: iii 番目グループ ${j}$ 番目被験者の共変量(例: 事前テストの点数)
- ${bar{x}}$: 共変量の全体平均
- ${\varepsilon_{ij}}$; 誤差項
分散分析(ANOVA)では共変量を考慮しませんが、ANCOVAモデルではこの${\beta(x_{ij} – \bar{x})}$が加わっている点が特徴です。
こうすることで、共変量の影響を統計的に制御しながら、グループ間の差(\alpha_i)を評価できます。
4-3. ANCOVAの前提条件
共分散分析を行う上では、分散分析で要求される条件に加えて、以下のような前提条件が課されます。
- 回帰直線の平行性: 各グループにおける ${y}$ と共変量 ${x}$ の回帰直線が平行であること
- 共変量と独立変数の独立性: 共変量が、意図的に操作される独立変数(グループ)と無関係であること
- 正規性・等分散性: 従来のANOVA同様、残差が正規分布に従い、各群の分散が等しいこと
これらの仮定が大きく崩れていると、ANCOVAの推定結果に偏りが生じたり、検定が歪んだりします。
4-4. ANCOVAの利点と欠点
- 利点
- 共変量が従属変数に与える影響を取り除き、誤差分散を減少させることで検定力が高くなる
- 独立変数の主効果を、より「純粋な」形で推定できる
- 欠点
- 前提条件を満たさない場合の解釈が難しい
- データ収集の段階で共変量を適切に測定しておく必要がある
- 回帰直線の平行性が成り立たない場合、別途交互作用を考慮したモデルなどを検討する必要がある
5. Pythonを用いたANCOVAの簡単な実行例
以下の例では、statsmodels
を使ってANCOVAに近い回帰モデルを実装することで、グループ(ダミー変数)と共変量の効果を同時に評価します。本格的なANCOVA機能を持つライブラリとしては pingouin
などもありますが、ここではベーシックな方法をお示しします。
import pandas as pd
import statsmodels.api as sm
import statsmodels.formula.api as smf
# 仮に3群(補習なし, A先生, B先生)、共変量として "事前テスト点数" があるデータフレームを作成
df = pd.DataFrame({
'score': [55, 60, 65, 70, 75, 62, 64, 67, 73, 78, 63, 68, 72, 80, 85], # 従属変数
'group': (['no_tutor']*5 + ['tutor_A']*5 + ['tutor_B']*5),
'pretest': [50, 55, 57, 58, 60, 54, 58, 59, 60, 63, 55, 58, 60, 61, 64] # 共変量
})
# グループをカテゴリ変数に変換
df['group'] = df['group'].astype('category')
# ANCOVAモデルを回帰として表現
# score ~ group + pretest は、"scoreをgroupとpretestの線形和で説明" という式
# ただし、回帰直線の平行性を仮定するため、交互作用項 (group:pretest) は入れない
model = smf.ols('score ~ C(group) + pretest', data=df).fit()
anova_table = sm.stats.anova_lm(model, typ=2)
print(model.summary())
print("\nANCOVAに相当するANOVA表:\n", anova_table)
ここでの C(group)
は、group
がカテゴリ変数であることを明示するために用いています。typ=2
は、それぞれの要因の平均平方和を適切に評価するための指定です(モデルや文献により typ=3
を使う場合もあります)。
- 回帰直線の平行性が疑わしい場合
score ~ C(group)*pretest
のように交互作用項も含めてフィッティングし、交互作用が有意かどうかを検定する方法もあります。交互作用が有意でなければ平行とみなせます。
6. 分散分析と共分散分析のまとめ
- 分散分析(ANOVA)
- 複数群(3群以上)の平均値に差があるかどうかを一度に検定する
- F値とp値を用いて仮説検定する
- 有意差がある場合は多重比較(Tukey HSDなど)により具体的にどこに差があるかを調べる
- 効果量(エータ平方、偏エータ平方など)を使えば、差の大きさを評価できる
複数群の平均値に差があるかどうかを統合的に検定でき、差がある場合は多重比較で詳細を調べます。
効果量を併用することで、統計的有意差の大きさを把握できます。
- 共分散分析(ANCOVA)
- ANOVAに回帰分析の考え方を組み込んだもの
- 従属変数に影響を与える可能性のある共変量を取り入れ、誤差分散を減少させて検定力を高める
- 回帰直線の平行性、共変量と独立変数の独立性、正規性・等分散性などの前提条件がある
- 教育分野や医学分野など、ベースラインの差を調整したい場合によく使われる
従属変数に影響を与える可能性のある共変量を取り込むことで、より洗練された分析を行います。
前提条件を満たせば、誤差分散を減らし検定力を向上させられるため、多岐にわたる応用事例があります。