Pythonでt検定を行う方法|SciPyの使い分けとp値・信頼区間の読み方
「2つのグループで平均点に違いがあるか」「同じ人の測定値が、実施前後で変化したか」。こうした平均値に関する問いを、標本データから検討する方法の一つがt検定です。
PythonのSciPyを使えば、少ないコードでt検定を実行できます。ただし、関数が正常に動くことと、データに適した分析ができていることは別です。対応の有無やデータの集め方を確認し、p値だけでなく平均差と信頼区間も読み取る必要があります。
この記事では、Welchのt検定と対応のあるt検定を、架空の得点データで実行します。コードの使い方に加えて、結果から言えることと、言えないことを整理しましょう。
目次
1.t検定とは?平均に関する仮説を調べる方法
t検定は、母平均について設定した仮説を、標本データから検討する統計的検定です。2つの母平均を比較する方法のほか、1つの母平均を基準値と比較する方法もあります。
例えば、独立した2群を比較する両側検定では、「2つの母平均は等しい」を帰無仮説、「2つの母平均は異なる」を対立仮説とします。手元の平均値が違うことだけで判断せず、データのばらつきや標本数も考慮します。
| 検定 | 比較する内容 | SciPyの関数 |
|---|---|---|
| 対応のないt検定 | 独立した2群の母平均 | stats.ttest_ind() |
| 対応のあるt検定 | 対応する測定値の差の母平均と0 | stats.ttest_rel() |
| 1標本のt検定 | 1つの母平均と指定した基準値 | stats.ttest_1samp() |
2群の人数が同じだからといって、対応のあるデータとは限りません。同じ人の前後の測定値など、一方の値と他方の値が意味のある組として結びついているかで判断します。
2.コードを書く前に確認する3つの条件
比較したいものは平均か
まず、何の差を調べたいかを具体的にします。得点や作業時間の平均を比べたいのか、合格率やクリック率などの割合を比べたいのかで、分析方法の検討が変わります。
この記事のコードは、数値データの平均を比較する入門例です。集計済みのクリック率を2つ並べるだけで、同じように検定できるわけではありません。割合を比較する場合は、件数と試行数、割り当て方法に合う分析を検討してください。
観測値の独立性と、対応関係はどうなっているか
対応のないt検定では、2群が独立しており、各群の観測値も互いに独立しているという前提を確認します。同じ人の繰り返し測定を、すべて別人のデータとして扱わないようにしましょう。
対応のあるt検定では、同じ人の前後の値を一組として扱い、その組どうしの独立性を考えます。例えば、10人をそれぞれ前後に測定した場合、比較するのは10組の差です。
分布の形、外れ値、欠損はどうなっているか
件数、平均、ばらつきに加えて、個々の値やグラフも確認します。少数の極端な値、入力ミス、単位の混在、同じデータの重複がないかを調べてください。
標本数が小さい場合は、正規分布を前提とする近似の妥当性に特に注意します。対応のあるt検定で確認するのは、前後それぞれの分布だけでなく、各組の「差」の分布です。
「30件あれば必ず使える」「正規性検定で有意でなければ問題ない」と機械的に判断することはできません。分布の偏りや外れ値、標本数、データの集め方を合わせて検討します。
検定の前に、平均値や中央値、p値の意味を整理したい方へ。データの特徴と、仮説検定の結果を読み取る際の注意点を具体例で解説しています。
データ分析の代表値と仮説検定|平均・中央値・p値の読み方を具体例で解説 記事を読む →3.PythonとSciPyで分析する準備
今回の例では、数値配列を扱うNumPyと、統計処理を行うSciPyを使用します。ターミナルで次のコマンドを実行してください。既存の環境で作業している場合は、プロジェクト用の仮想環境を使うと管理しやすくなります。
python -m pip install numpy "scipy>=1.11"
この記事では、検定結果から信頼区間を取得する機能も使います。コードはSciPy 1.17.0で動作確認しており、後述するWelchのt検定の信頼区間取得にはSciPy 1.11.0以降が必要です。
以下のデータは、実行方法を説明するために作成した架空の数値です。実際の授業や教材の効果を示す調査結果ではありません。
4.対応のない2群をWelchのt検定で比較する
独立した対象者から得られた2群の得点を想定します。ここでは、母分散が等しいことを仮定しないWelchのt検定を使い、2つの母平均が異なるかを両側検定で調べます。
SciPyでは、ttest_ind()にequal_var=Falseを指定します。指定しない場合の既定値はTrueで、等分散を仮定する検定になるため、意図する方法を明示しましょう。
import numpy as np
from scipy import stats
# 架空の得点データ:AとBは独立した対象者
a = np.array(
[62, 65, 68, 70, 72, 74, 75, 78, 80, 83],
dtype=float,
)
b = np.array(
[64, 68, 70, 72, 75, 77, 79, 82, 85, 88],
dtype=float,
)
# 差の向きを「B - A」に統一する
result = stats.ttest_ind(
b,
a,
equal_var=False,
alternative="two-sided",
nan_policy="raise",
)
ci = result.confidence_interval(confidence_level=0.95)
print(f"A: n={a.size}, mean={a.mean():.2f}")
print(f"B: n={b.size}, mean={b.mean():.2f}")
print(f"Mean difference (B - A): {b.mean() - a.mean():.2f}")
print(
f"t={result.statistic:.3f}, "
f"df={result.df:.2f}, p={result.pvalue:.6f}"
)
print(f"95% CI: [{ci.low:.2f}, {ci.high:.2f}]")
実行すると、次の結果が得られます。dfは自由度、95% CIは母平均の差「B-A」の95%信頼区間を表しています。
A: n=10, mean=72.70
B: n=10, mean=76.00
Mean difference (B - A): 3.30
t=1.027, df=17.63, p=0.318519
95% CI: [-3.46, 10.06]
標本平均に差があっても、有意になるとは限らない
この標本では、Bの平均点がAより3.30点高くなっています。しかし、事前に有意水準を5%と決めていた場合、p値は0.05を上回るため、母平均が等しいという帰無仮説を棄却しません。
これは「AとBは完全に同じ」という意味ではありません。母平均の差の95%信頼区間は-3.46点から10.06点で、差の推定には幅があります。標本平均の違いと、母平均についての判断を分けて読み取りましょう。
また、Welchのt検定を選んでも、観測値の独立性や極端な外れ値の問題が自動的に解決するわけではありません。実データに置き換える際は、計算前の確認が必要です。
5.同じ人の前後を、対応のあるt検定で比較する
次は、同じ10人について、前後に同じ尺度で得点を測定した状況を想定します。各配列の同じ位置が同じ人になるように揃え、ttest_rel()で「後-前」の差の母平均が0かを調べます。
import numpy as np
from scipy import stats
# 架空のデータ:同じ位置は同じ対象者
before = np.array(
[55, 62, 70, 68, 74, 80, 60, 72, 65, 78],
dtype=float,
)
after = np.array(
[58, 61, 74, 70, 74, 85, 62, 73, 68, 79],
dtype=float,
)
# 差の向きは「後 - 前」
difference = after - before
result = stats.ttest_rel(
after,
before,
alternative="two-sided",
nan_policy="raise",
)
ci = result.confidence_interval(confidence_level=0.95)
print(f"Pairs: {before.size}")
print(f"Mean difference (after - before): {difference.mean():.2f}")
print(
f"t={result.statistic:.3f}, "
f"df={result.df:.2f}, p={result.pvalue:.6f}"
)
print(f"95% CI: [{ci.low:.2f}, {ci.high:.2f}]")
実行結果は次のとおりです。この例では10組の差を使って計算しており、測定値が前後にあるからといって、20人分の独立したデータとして扱っているわけではありません。
Pairs: 10
Mean difference (after - before): 2.00
t=3.464, df=9.00, p=0.007115
95% CI: [0.69, 3.31]
前後の差が有意でも、原因が特定されたわけではない
有意水準5%の両側検定では、差の母平均が0という帰無仮説を棄却します。標本での平均差は2点で、対応する母平均差の95%信頼区間は約0.69点から3.31点です。
ただし、この結果だけで「新しい教材によって2点上がった」とは言えません。通常の学習、同じ問題への慣れ、測定条件の変化など、ほかの説明があり得るためです。
対応のある検定は、一人ひとりの差を分析する方法です。教材や施策の因果的な効果を調べたい場合は、比較対象の設定や無作為な割り当てなど、研究・実験の設計から検討します。
t検定で使うt分布を、ほかの分布と整理して理解したい方へ。標準正規分布・t分布・カイ二乗分布・F分布の役割と、検定での使い分けを解説しています。
標準正規分布・t分布・カイ二乗分布・F分布の違い|検定の使い分けと条件を整理 記事を読む →6.p値・平均差・信頼区間を一緒に読む
p値は、帰無仮説と分析上の前提の下で、観測された検定統計量と同程度以上に極端な値が得られる確率です。「帰無仮説が正しい確率」や「結果が偶然である確率」を直接表したものではありません。
また、p値が小さいことと、差が実務上重要であることは別です。点数の差なら、その数点がどのような意味を持つのか、試験の尺度や判断目的に照らして考えます。
| 確認する数値 | 読み取ること |
|---|---|
| 標本数 | 何人・何件・何組のデータから計算したか |
| 各群の平均・平均差 | 観測された差の向きと大きさ |
| t値・自由度 | 検定で使用した統計量と分布の条件 |
| p値 | 帰無仮説と前提の下での、検定統計量の極端さ |
| 信頼区間 | 母平均や母平均差の推定の幅 |
95%信頼区間は、前提が成り立つ状況で同じ方法による標本抽出と区間計算を繰り返したとき、作られた区間の約95%が真の値を含むという性質に基づきます。「観測データの95%がこの範囲に入る」という意味ではありません。
有意水準、両側・片側の別、比較する項目は、結果を見る前に決めておきましょう。有意にするために後から検定の向きや対象データを変えると、結果を適切に解釈できなくなります。
7.実データに置き換えるときの注意点
欠損値を、理由を確認せず削除しない
掲載コードでは、nan_policy="raise"を指定し、NaNが含まれる場合はエラーにしています。欠損を自動的に無視するよりも、まず、なぜ値が欠けているかを確認するためです。
対応のあるデータでは、前後の配列から別々に欠損行を削除すると、異なる人どうしが組になる危険があります。対象者IDで対応を確認し、前後が揃った組の扱いを決めてください。除外件数と理由も記録します。
外れ値は、検定結果を見てから都合よく除外しない
極端な値が見つかったら、入力ミスや測定上の問題か、実際に起きた値かを確認します。実際の観測値を、p値が小さくなるという理由だけで削除してはいけません。
データの特徴に応じて別の分析方法を検討する場合も、何を比較する方法なのかを確認しましょう。例えば、順位に基づく検定への変更は、単純に「平均差を調べるt検定の前提を外したもの」とは限りません。
検定できたことと、一般化できることを分ける
手元に集めやすかった人だけのデータから、すべての利用者や生徒について結論を広げることには限界があります。対象者をどう選んだか、どの範囲に結果を当てはめたいかを明記してください。
結果を報告する際は、検定名、標本数、平均差、信頼区間、p値に加えて、データの集め方と分析上の制約も残します。数値だけを抜き出すより、後から判断の過程を確認しやすくなります。
Pythonでの分析をさらに学びたい方へ。PythonとRの選び方を整理し、同じデータを使って集計や分析を試す入門例を紹介しています。
データ分析はPythonとRどちらから学ぶ?選び方と同じデータで試す入門例 記事を読む →8.Pythonのt検定でよくある質問
必要なサンプルサイズは何件ですか?
一律の件数では決まりません。検出したい平均差、ばらつき、有意水準、検出力、対応の有無を踏まえて計画します。この記事の10件という設定はコードの説明用であり、実際の分析に十分な件数を示すものではありません。
p値が0.05以上なら、差がないと判断できますか?
差がないことの証明にはなりません。差を検出するには情報が不足している可能性もあるため、平均差と信頼区間を確認します。実用上同等であることを示したい場合は、許容できる差を定め、同等性検定など別の設計を検討します。
3群以上なら、必ず分散分析を使いますか?
群数だけでは決められません。独立性、対応の有無、比較したい仮説に合わせて、分散分析や回帰モデルなどを検討します。複数の比較を行う場合は、検定を繰り返すことによる多重性への対応も必要です。
結果がNaNになった場合はどうすればよいですか?
欠損、無限大、データ数の不足、ばらつきがないデータなどを確認してください。対応のある検定では、差がすべて同じ値になっていないかも確認します。NaNを「有意差なし」として処理しないようにしましょう。
参考資料
- SciPy公式ドキュメント:ttest_ind
- SciPy公式ドキュメント:ttest_rel
- SciPy公式ドキュメント:ttest_1samp
- NIST:Two-Sample t-Test for Equal Means
- Penn State:Comparing Two Population Parameters
- 米国統計学会:統計的有意性とp値に関する声明
Learning Tools
記事を検索したい方はここから!
記事を検索
関連記事や、今の内容に近いテーマをすぐに検索できます。
例: AI / 情報Ⅰ / Python / 統計 / 資格 / 学習法