メインコンテンツへスキップ
ブログ一覧に戻る
統計・データサイエンス

分散分析(ANOVA)|3 群比較の要点と事後検定・効果量の実務ガイド

2025年10月28日
最終更新: 2026年10月8日
13分で読めます

この記事でわかること

分散分析で3群以上の平均を比べる手順を、各5人の仮想データとPythonで解説します。古典的ANOVAとWelch、TukeyとGames–Howell、調整済み信頼区間、η²・ω²の意味を確認。反復測定や二元配置への分岐、欠測・外れ値、標本数と停止条件も整理し、全体の有意差をそのまま採用理由にしない判断を支えます。

3案の平均を比べて「どれを採用するか」を決めたいとき、分散分析(ANOVA)は比較の出発点になります。ただし、全体のp値が小さくても、すべての案が違うとは限りません。どの組にどれだけ差があり、その差が運用上意味を持つかは、比較ごとの推定と区間で確かめます。

本記事は、独立した3群の一元配置ANOVAを中心に、Welchの方法、Tukey・Games–Howell、多重比較、効果量、反復測定や二元配置に進む条件まで扱います。数値とコードはすべて仮想教材であり、実際の施策成果を示していません。

30秒で要点

  • 一元配置ANOVAの帰無仮説は、比較するすべての母平均が等しいこと。棄却して分かるのは、少なくとも一つの差があることです。
  • 古典的ANOVAは独立性・群内の正規分布・共通分散を仮定します。等分散を置けない独立群にはWelchを検討します。
  • 全組の平均差を比較するなら、共通分散の設定ではTukey、不等分散の設定ではGames–Howellなどを選び、調整済みp値と区間を示します。
  • η²は「売上が何%増えたか」ではありません。元の単位の平均差、区間、費用と必要な改善幅も併記します。

比較する群と、知りたい量を先に固定する

一元配置の「一元」は、説明する要因が一つという意味です。たとえば手順A・B・Cという要因に三つの水準があり、各人の作業時間を測る場合です。人数が多い、列が多いという意味ではありません。

表が収まらない場合は、横にスクロールできます

データの取り方検討する分析
別々の人がA・B・Cのどれか一つを使う独立群の一元配置ANOVAやWelch ANOVA
同じ人がA・B・Cをすべて使う反復測定。人内相関、実施順序、持ち越しを扱う
手順A・B・Cと、初心者・経験者を同時に比較する二元配置や回帰。要因間の交互作用を検討する
3つのLPの購入率を比べる購入の有無と各群の分母を持つ比率の分析。集計済みCVRをそのまま連続測定として並べない

同じ店舗の多数の客や、同じ人の多数の操作を、独立した反復として数えてよいかも確認します。ANOVAは、標本が依存している問題や、そもそも群の背景が違う問題を消してくれません。

分散を比べて、平均の違いを調べる仕組み

三つの母平均をμA、μB、μCとすると、帰無仮説は μA = μB = μC。対立仮説は「すべてが等しいわけではない」です。

古典的な一元配置ANOVAは、観測値と全体平均のずれを、群平均と全体平均のずれ(群間平方和)と、各観測と群平均のずれ(群内平方和)に分けます。群数をk、全人数をNとすると、群間の自由度はk - 1、群内はN - kです。

F = 群間平均平方 / 群内平均平方。平均平方は平方和を自由度で割ったものです。同じ母平均・共通分散などの仮定の下で、この比が大きいほど帰無仮説と整合しにくくなります。NISTのANOVA表と検定

ここで検定しているのは母平均であり、「三群の分散が等しいか」自体を検定しているのではありません。分散の情報を使うことと、検定対象が分散であることを区別します。

各5人の作業時間で、ANOVA表を計算する

別々の15人を三つの手順に5人ずつ割り付け、同じ課題の完了時間を測ったとする仮想例です。数値の単位は分。各人は一度だけ観測され、表の同じ位置に対応関係はありません。

表が収まらない場合は、横にスクロールできます

手順作業時間(分)平均(分)標本標準偏差(分)
A3.2、3.5、3.0、3.4、3.13.240.207
B3.6、3.8、3.7、3.5、3.93.700.158
C3.1、3.0、2.9、3.2、3.03.040.114

以下は各ブロック単独で実行可能です。2026年10月4日にPython 3.12、NumPy 2.5.3、SciPy 1.16.2、Matplotlib 3.10.7、statsmodels 0.14.5で確認しました。f_oneway(equal_var=False)と、ここで使うGames–Howellの引数は、実行環境で利用できることを確認してから使ってください。

import numpy as np
from scipy import stats
from statsmodels.stats.oneway import confint_effectsize_oneway

groups = [np.array(x) for x in [
    [3.2, 3.5, 3.0, 3.4, 3.1],
    [3.6, 3.8, 3.7, 3.5, 3.9],
    [3.1, 3.0, 2.9, 3.2, 3.0],
]]
all_values = np.concatenate(groups)
N, k = len(all_values), len(groups)
ss_between = sum(len(x) * (x.mean() - all_values.mean())**2 for x in groups)
ss_within = sum(((x - x.mean())**2).sum() for x in groups)
ss_total = ss_between + ss_within
df_between, df_within = k - 1, N - k
ms_between, ms_within = ss_between / df_between, ss_within / df_within
classic = stats.f_oneway(*groups, equal_var=True)
welch = stats.f_oneway(*groups, equal_var=False)
eta_sq = ss_between / ss_total
omega_sq = (ss_between - df_between * ms_within) / (ss_total + ms_within)
effect_ci = confint_effectsize_oneway(
    classic.statistic, (df_between, df_within), alpha=0.05, nobs=N
)
print(f"SS between={ss_between:.6f}, within={ss_within:.6f}, total={ss_total:.6f}")
print(f"classical F({df_between},{df_within})={classic.statistic:.6f}, p={classic.pvalue:.9f}")
print(f"Welch F={welch.statistic:.6f}, p={welch.pvalue:.9f}")
print(f"eta_sq={eta_sq:.6f}, omega_sq={omega_sq:.6f}")
print(f"classical-model eta_sq 95% CI=[{effect_ci.eta2[0]:.6f}, {effect_ci.eta2[1]:.6f}]")

表が収まらない場合は、横にスクロールできます

変動平方和(分²)自由度平均平方(分²)
群間1.14533320.572667
群内0.324000120.027000
全体1.46933314—

古典的ANOVAではF(2,12)≈21.210、p≈0.000115です。ただし「A・B・Cの全組で差がある」「Cを導入すれば必ず速くなる」とは結論しません。どの差をどの範囲まで推定できるかを次に調べます。

不等分散ならWelchを検討し、診断は省略しない

SciPyのf_onewayは、equal_var=Trueを古典的ANOVA、FalseをWelch ANOVAとしています。今回のWelchの結果はF≈26.366、p≈0.000389です。二つを併記したのは方法の違いを学ぶためであり、小さいp値が出た方を採用する手順ではありません。

表が収まらない場合は、横にスクロールできます

確認する条件最小限の点検
観測の独立性人・店舗・日などのIDと割付単位を確認。繰り返しを別人扱いしない
群内の分布生データ、箱ひげ図、残差のQ-Qプロット。混ぜた全群の分布だけで判断しない
群の分散と人数群別の標準偏差・人数と、ばらつきの違いが生じる測定上の理由を確認
欠測・極端値群別の欠測理由と除外規則。観測後に都合の悪い値を消さない

各5人では、正規性検定が非有意でも分布を十分に確かめたことにはなりません。Welchも、独立性や正規分布に基づく小標本の近似を不要にする方法ではありません。重い裾、強い歪み、小さく不均衡な群などがあるなら、計測・推定対象・分析計画を再検討します。正規性検定の定義

全体の検定と、どの組が違うかの比較を分ける

3群なら比較はA-B、A-C、B-Cの3組です。各組に無調整の5%検定を繰り返すと、家族内で少なくとも一つを誤検出する確率を5%に管理したことにはなりません。比較どうしはデータを共有するため、常に独立という仮定で 1 - 0.95³ と計算することもできません。

比較の家族は、まとめて誤りを管理したい仮説の集合です。主要指標の全3組なのか、対照群との2組だけなのか、複数指標も含むのかを先に定めます。結果を見て都合のよい組だけを家族に残すことは避けます。

表が収まらない場合は、横にスクロールできます

問いと条件選択肢出力の読み方
共通分散の独立群で全組の平均差Tukey HSD。人数が異なる場合はTukey–Kramer全組を対象とする同時信頼区間と調整済みp値
共通分散を置かない独立群で全組Games–Howell群ごとの分散と自由度を使う近似的な多重比較
事前に決めた有限個の比較や対比Bonferroni、Holmなど定義した家族の誤検出を管理する設計
多数の探索候補から次の研究対象を探すFDRを管理する方法など少なくとも1誤検出の確率を管理するFWERとは目標が違う
NISTのTukey法とBonferroni法は、比較の集合と区間の同時被覆を区別しています。HolmやFDRの方式もstatsmodelsの多重検定APIで明示的に選べます。FDRは棄却した集合に含まれる誤棄却割合の期待値を管理する考え方で、個別の発見が正しい確率を返すものではありません。

全体検定が有意なら事後比較に進む、という報告の順序は分かりやすいものです。ただし事前に定めた対比とその多重性管理を、常に全体検定の有意性で開閉する必要があるわけではありません。どの仮説を主要とする設計かを先に決めます。

Pythonで全3比較の調整済み区間を得る

SciPyのtukey_hsdは、equal_var=FalseでGames–Howellを実装しています。ここでも両方を教材として表示します。実務で二つの方法から有意な行だけを取り出すためのコードではありません。

import numpy as np
from scipy import stats

groups = [np.array(x) for x in [
    [3.2, 3.5, 3.0, 3.4, 3.1],
    [3.6, 3.8, 3.7, 3.5, 3.9],
    [3.1, 3.0, 2.9, 3.2, 3.0],
]]
pairs = [(1, 0, "B-A"), (2, 0, "C-A"), (2, 1, "C-B")]
for name, equal_var in [("Tukey", True), ("Games-Howell", False)]:
    result = stats.tukey_hsd(*groups, equal_var=equal_var)
    ci = result.confidence_interval(confidence_level=0.95)
    for i, j, label in pairs:
        print(f"{name} {label}: diff={result.statistic[i,j]:.3f} min, "
              f"adjusted p={result.pvalue[i,j]:.6f}, "
              f"95% CI=[{ci.low[i,j]:.3f}, {ci.high[i,j]:.3f}]")

古典的な共通分散モデルでのTukeyの結果は次の通りです。

表が収まらない場合は、横にスクロールできます

差の方向平均差(分)95%同時信頼区間(分)読み方
B - A+0.46+0.183〜+0.737Bの方が長い方向
C - A-0.20-0.477〜+0.077ゼロをまたぎ、同等とも短いとも確定しない
C - B-0.66-0.937〜-0.383Cの方が短い方向

時間が小さい方が望ましいため、差の符号を確認します。C-Aの標本差-0.20分は-12秒ですが、区間は約-28.64〜+4.64秒です。仮に導入には少なくとも10秒の短縮が必要でも、C-Aの区間全体がその基準を超える短縮を示したわけではありません。

仮想の独立3群各5人の作業時間。上段は個人の測定値と群平均の95%t区間、下段はTukeyで調整したB-A、C-A、C-Bの平均差と95%同時信頼区間。C-Aはマイナス0.477分からプラス0.077分でゼロをまたぐ。
仮想例。上段の群ごとの95%区間は未調整、下段は全3組に対するTukeyの95%同時区間です。比較の判断は下段の差の区間で行い、上段の区間の重なりだけでは決めません。共通分散・独立性などのモデル条件があります。

Games–Howellでは区間の幅が組ごとに変わります。この教材でのC-Aは約-0.521〜+0.121分です。どちらの方法でも、非有意な比較を「差なし」と言い換えません。

効果量は、何のばらつきを分母にしたかを伝える

一元配置のη²(イータ二乗)は 群間平方和 / 全体平方和。この例では約0.779です。標本内の変動の約77.9%が群の違いに対応するという記述で、作業時間が77.9%短くなる意味ではありません。割付や交絡の検討なしに因果的な説明率とも呼べません。

ω²(オメガ二乗)は、この古典的な独立群モデルでは (群間平方和 - (k - 1) × 群内平均平方) / (全体平方和 + 群内平均平方)。約0.729です。標本のη²の上方バイアスを軽減する推定量ですが、誤差がなくなるわけではありません。別の標本では負になる場合もあり、その扱いを報告せず隠さないようにします。

partial η²は 対象効果の平方和 / (対象効果の平方和 + その誤差平方和)。ここではη²と一致しますが、複数要因や反復測定では分母が変わります。研究設計の違う値を、そのまま効果のランキングに使えません。効果量の定義と設計依存性

最初のコードには、古典的な固定効果一元配置モデルについて、非心F分布を反転して得るη²パラメータの95%区間も含めました。nobs=15を指定した結果は約0.389〜0.861で、点推定だけでは大きさを絞り切れないことが分かります。これはλ = N × f²、η² = f² / (1 + f²)というパラメータ化の区間です。statsmodelsの説明と境界上の制約を確認し、WelchのF値や反復測定のpartial η²に流用しません。

元の単位の平均差は「何分を節約できそうか」という問い、η²は「群の違いと変動がどの程度対応するか」という問いに答えます。片方で他方を置き換えず、費用・品質低下・導入対象も合わせて評価します。

図を再現し、平均区間と多重比較を混同しない

次の図は各群の生データ・箱ひげ・平均の95%t区間を描きます。各5人なので、群ごとの区間には自由度4のt分位点を用います。これは前節のTukey同時区間とは別です。平均のt区間の式

import numpy as np
import matplotlib.pyplot as plt
from scipy import stats

groups = [np.array(x) for x in [
    [3.2, 3.5, 3.0, 3.4, 3.1],
    [3.6, 3.8, 3.7, 3.5, 3.9],
    [3.1, 3.0, 2.9, 3.2, 3.0],
]]
fig, axes = plt.subplots(1, 2, figsize=(9, 4))
axes[0].boxplot(groups, tick_labels=["A", "B", "C"])
for i, values in enumerate(groups, start=1):
    axes[0].scatter(i + np.linspace(-0.08, 0.08, len(values)), values)
axes[0].set(ylabel="Task time (minutes)", title="Synthetic individual observations")
means = [x.mean() for x in groups]
half_width = [stats.t.ppf(0.975, len(x)-1) * stats.sem(x) for x in groups]
axes[1].errorbar([0, 1, 2], means, yerr=half_width, fmt="o", capsize=5)
axes[1].set(xticks=[0, 1, 2], xticklabels=["A", "B", "C"],
            ylabel="Mean time (minutes)", title="95% t CI, not simultaneous")
for ax in axes:
    ax.set_ylim(2.7, 4.1)
fig.tight_layout()
fig.savefig("anova-observations-and-mean-ci.png", dpi=150)
plt.close(fig)
print("Saved anova-observations-and-mean-ci.png")

小標本では箱ひげだけだと点数の少なさが伝わりにくいため、生データと人数も残します。図の軸・単位・区間の方式・比較対象をキャプションに書くと、会議用に図だけを抜き出したときの誤読も減らせます。

二元配置・反復測定・順位法へ進む条件

二元配置では、たとえば手順と習熟度を要因にします。手順の差が初心者と経験者で変わることが交互作用です。その可能性を無視し、全員を平均した「手順の主効果」だけで各層の結論を決めないようにします。要因の組合せごとの人数と観測が必要であり、セルが空の場合や著しく不均衡な場合は解釈も難しくなります。多要因モデルと残差点検

反復測定では同じ人の値が相関するので、独立群のf_onewayへそのまま渡しません。三水準以上の被験者内効果を通常の単変量反復測定ANOVAで扱う場合は、差どうしの分散に関する球面性にも注意が必要です。違反を扱う自由度補正や、相関構造を明示する混合モデルなどを設計に応じて検討します。実装の対応範囲も確認し、たとえばstatsmodelsのAnovaRMは、完全に釣り合った被験者内設計のみを支持し、球面性違反の補正は未実装としています。

順位に基づく方法では、独立群のKruskal–Wallisなどが候補です。ただし平均差の検定とは同じではなく、中央値の違いと読むにも分布形の条件が関わります。小標本で近似が適切か、全体検定後の比較をどう管理するかも必要です。SciPyのKruskal–Wallis

対数変換やブートストラップも選択肢ですが、前者は比較する量を変え、後者は独立した観測単位を保った再標本化が必要です。どの方法も、欠測による選択や計測の偏りを自動的に修復するものではありません。

採用前に残す最小の分析メモ

  1. 対象と設計:誰をどの単位で割り付け、何をいつ測るか。主要指標と望ましい差の方向も書く。
  2. 比較の計画:全体仮説、主要な比較の家族、分析法、多重性管理、有意水準、必要な改善幅を決める。
  3. 人数と終了:想定する平均差・ばらつき・配分から検出力を計画する。全体検定の検出力が高くても、重要な各組の比較に十分とは限らない。
  4. 品質点検:群別人数、欠測理由、測定誤り、残差や生データを確認する。
  5. 報告:平均と標準偏差、ANOVA表、主要比較の差と区間、効果量、費用と残る不確実性をまとめる。

結果を見るたびに人数を増やしたり、有意になった比較だけで終了したりすると、固定時点の検定の保証をそのまま使えません。途中判定は別の設計として扱います。継続監視と固定標本推論の違い

練習として、3つのLPで購入率を比較するなら、最初に何を集めるでしょうか。答えは率だけでなく群別の購入数と対象者数、割付・期間・重複の情報です。同じ10人が3画面を使うなら、30人の独立群ではなく10人の反復測定です。最後に「全体で有意、C-Aは非有意」なら矛盾でしょうか。全体は少なくとも一つの差を検出する問いなので、矛盾ではありません。

2群の平均と対応関係を確認し直す場合はt検定の実務ガイド、実験前の割付や反復の考え方は実験計画法で扱っています。

よくある質問(FAQ)