【python】分散分析(ANOVA)の基礎から応用まで|統計的仮説検定
こんにちは、青の統計学です。
今回は、分散分析について解説いたします。
分散分析(ANOVA)
分散分析(ANOVA)は、統計学において複数の群間で平均値に有意な差があるかどうかを判断する手法です。
管理人の主観ですが、ビジネスの面で頻繁に使う場面があります。開発やアナリストサイドだけでなく、ビジネスサイドの人材でも知っておいて損はないでしょう。
本記事では、分散分析の基本概念からPythonでの実践方法までを解説し、初心者でも理解できるように説明します。
F値とF分布について|統計的仮説検定
一元分散分析 (One-way ANOVA) は、1つの因子によって群が分けられたデータを分析するための方法です。
F値と呼ばれる統計量を使い、帰無仮説と対立仮説を検討します。
$$F value= \frac{\frac{群間の平方和}{群間の自由度}}{\frac{群内の平方和}{群内の自由度}}$$
群間の平方和 (SSB: Sum of Squares Between) は、各群の平均値が全体の平均値からどれだけずれているかを表します。
群内の平方和 (SSW: Sum of Squares Within) は、各群内のデータがその群の平均値からどれだけずれているかを表します。
群間の自由度 (df_between) は、群の数から1を引いた値で計算されます(群数 – 1)。
群内の自由度 (df_within) は、全データ数から群数を引いた値で計算されます(全データ数 – 群数)。
そしてこのF値は F分布に従います。
そしてF分布は、2つの自由度に従います。群間の自由度と群内の自由度です。
$$F value= \frac{\frac{群間の平方和}{df_{between}}}{\frac{群内の平方和}{df_{within}}}〜F(df_{between}, df_{within})$$
帰無仮説 (H0): 各群の母平均は等しい。
対立仮説 (H1): 少なくとも1つの群の母平均が他の群と異なる。
具体的な例で言うと、何らかの介入(広告や高等教育の実施、新薬の投与)によって平均値に意味のある差が生まれたかどうかを判断します。
p値が有意水準(例: 0.05)より小さい場合、帰無仮説を棄却し、対立仮説を採択します。
分散分析で分かるのは、「どの水準にも差はないのでしょうか?」という帰無仮説が否定された場合、「水準間に差はあります。ただし、どの水準とどの水準の間の差が有意かまでは分からないです。」というところまでです。
CODE|python
3群のデータを用意して、平均値に差があるかどうか確認します。
データは、以下のようにします。
group1 | group2 | group3 | |
生徒1 | 12 | 22 | 32 |
生徒2 | 15 | 24 | 34 |
生徒3 | 16 | 26 | 36 |
生徒4 | 18 | 28 | 38 |
生徒5 | 20 | 30 | 40 |
group1:補修を受けないクラスのテストの点数
group2:A先生の補修を受けたクラスのテストの点数
group3:B先生の補修を受けたクラスのテストの点数
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]
group3 = [32, 34, 36, 38, 40]
#一元分散分析を実行し、F値とp値を求めます。
f_value, p_value = stats.f_oneway(group1, group2, group3)
print("F値:", f_value)
print("p値:", p_value)
#p値が有意水準より小さいかどうかを判断します。
alpha = 0.05
if p_value < alpha:
print("帰無仮説を棄却し、対立仮説を採択。")
else:
print("帰無仮説を採択。")
F値: 50.34931506849327 p値: 1.4573895567680738e-06 帰無仮説を棄却し、対立仮説を採択。
さて、有意な差はあるようです。
先ほど申し上げた通り、分散分析の有意では「どの群間に有意差があるかわからない」です。
一元分散分析で帰無仮説が棄却された場合、どの群間に有意な差があるかを特定するために、多重比較が必要になります。
ポストホックテストとも呼ばれる多重比較方法には、Tukey HSD (Honestly Significant Difference) やBonferroni補正などがあります。
多重比較は、比較する群の数が多いほど検定の回数が多くなり、検定の回数が大きくなるほど、少なくとも一つの群間で有意になる確率が高くなるので、有意水準を調節する必要があります。
有意差が出るまで統計的仮説検定をしてはいけません。
詳しくは以下のコンテンツをご覧ください。
CODE|python|Turkey HSBテスト
Pythonを使ってTukey HSDテストを実行する例を示します。
Tukey HSD(Honestly Significant Difference)テストは、一元分散分析(ANOVA)の後に行われるポストホック検定の一つで、複数の群間の平均値の違いをペアごとに比較します。
この手法は、多重比較問題に対処するために設計されています。
Tukey HSDテストでは、次の手順でペアごとの比較を行います。
1:群間のすべてのペアについて、平均値の差を計算する。
2:それぞれのペアについて、Tukey HSDの基準値を計算する。
3:平均値の差が基準値よりも大きい場合、そのペアについて有意な差があると判断する。
Tukey HSDの基準値は、以下の数式によって計算されます。
$$Q = \sqrt{\frac{MSW}{n}} × q(α, df_{between}, df_{within})$$
MSW(Mean Square Within): 群内の平方和を群内の自由度で割った値。一元分散分析の結果から得られます。
n: 各群のデータ数。本手法では、すべての群のデータ数が等しいことが前提となります。
q(α, df_between, df_within): スチューデント化範囲分布(Studentized range distribution)のパーセント点。
αは有意水準(通常は0.05)、\(df_{between}\)と\(df_{within}\)は群間と群内の自由度です。
from statsmodels.stats.multicomp import pairwise_tukeyhsd
data = np.concatenate([group1, group2, group3])
groups = ['group1'] * len(group1) + ['group2'] * len(group2) + ['group3'] * len(group3)
tukey_result = pairwise_tukeyhsd(data, groups, alpha=alpha)
print(tukey_result)
便利なメソッドがあるため、簡単に計算ができます。
このような結果が出力されます。
どの群間にも有意差はありましたね。補習に効果はあり、さらにA先生の補習よりもB先生の補習の方が優れていると言うことがわかりました。
ここまで0.05と設定してきた有意水準ですが、経験的に設定してきたものです。
かなり議論がある部分ですので、どのように設定すべきかを知りたい方は以下のコンテンツをご覧ください。
【仮説検定】p値をゼロから解説(第一種の過誤,第二種の過誤,検出力)
効果量|エータ平方
では、最後に分散分析に関連して効果量についてご紹介します。
η2(エータ平方)は、一元分散分析(ANOVA)において効果量を測る指標の一つで、説明変数(群間の変数)が目的変数(測定データ)に与える影響の大きさを示します。
η2は、群間の平方和(Sum of Squares Between, SSB)を全体の平方和(Sum of Squares Total, SST)で割って求められます。
$$η2 = \frac{SSB}{SST}$$
η2の値は0から1の範囲になり、値が大きいほど説明変数が目的変数に大きな影響を与えていることを示します。
η2の評価基準は、研究分野や目的によって異なることがありますが、一般的な目安として以下の基準が提案されています。
0.01未満: 効果がほとんどない(無視できる) 0.01~0.06: 小さい効果 0.06~0.14: 中程度の効果 0.14以上: 大きな効果
ss_between = np.sum(np.square(np.mean(group1) - data.mean()) + np.square(np.mean(group2) - data.mean()) + np.square(np.mean(group3) - data.mean()))
ss_within = np.sum(np.square(group1 - np.mean(group1)) + np.square(group2 - np.mean(group2)) + np.square(group3 - np.mean(group3)))
ss_total = ss_between + ss_within
eta_squared = ss_between / ss_total
print("η2:", eta_squared)
η2: 0.6266302957974598
今回のテストの補習については、凄まじい効果があるとわかりますね汗
分散分析の応用例|特徴量選択
分散分析(ANOVA)は、特徴量選択の一環としても利用されます。
特徴量選択では、多数の特徴量の中から、目的変数に対して影響力のある特徴量のみを選択することを目的としています。
→それにより、結果の解釈性をあげたりします。前処理の一部ですね。
ANOVAは、特にカテゴリカル変数(カテゴリデータ)の特徴量に対して効果的です。
実例は以下のコンテンツをご覧ください。
【SHAP】スタッキング(stacking)で特徴量の解釈はできるのか|pythonアンサンブル学習
具体的な事例を通して分散分析を学びたい方は、以下のコンテンツをご覧ください。
【統計検定2級で最も手強い(主観)】分散分析について解説します①