- 技術 💻
p値とは|意味・有意水準・よくある誤解をPythonで実演
結論
p値とは、帰無仮説が正しいとしたとき、観測した結果以上に極端な結果が出る確率です。小さいほど「偶然だけでは説明しにくい」ことを示します。
この記事でわかること
- コイン10回の手計算と、検定5種のSciPyコード
- 米国統計学会の6原則と、誤解7つの正しい読み方
- pハッキングで偽陽性が5%→52%になる実測
p値は「差が無い(効果が無い)」という仮説を仮に置き、その仮説のもとで今回のデータがどれだけ珍しいかを表す数です。p値が有意水準(多くは0.05)より小さいとき、「有意差あり」と判定します。
flowchart TD
A[帰無仮説を置く<br>例 差は無い] --> B[データから<br>t値などを計算]
B --> C[p値 = 帰無仮説のもとで<br>これ以上極端になる確率]
C --> D{p値 < 有意水準<br>多くは 0.05}
D -->|はい| E[有意差あり<br>帰無仮説を棄却]
D -->|いいえ| F[有意差があるとは<br>言えない]
急いでいる人向けに、よく調べられることの答えを先にまとめます。
| 知りたいこと | 答え | 詳しい節 |
|---|---|---|
| p値とは | 帰無仮説のもとで、今回以上に極端な結果が出る確率 | p値とは |
| p < 0.05 の意味 | 差が無いなら5%未満でしか起きない結果。有意と判定 | 有意水準 |
| p値が小さいほど | 帰無仮説とデータが合わない。効果の大きさではない | 誤解 |
| p値が大きいとき | 差があるとは言えない。差が無い証明ではない | 誤解 |
| 求め方 | t値などを計算し、分布の外側の面積を出す | 求め方 |
| Python で | scipy.stats.ttest_ind(a, b).pvalue |
Python |
| 片側と両側 | 両側が基本。片側は両側の半分になる | 片側と両側 |
| 0.05 の理由 | フィッシャーが1925年に目安として示した値 | 有意水準 |
確認環境:Ubuntu 24.04.4 LTS・Python 3.11.15・NumPy 2.4.6・SciPy 1.17.1・statsmodels 0.15.0。コイン投げの二項検定、Welch と Student の t 検定、対応のある t 検定、Mann-Whitney の U 検定、カイ二乗検定(補正あり・なし)、フィッシャーの正確検定、適合度検定、相関係数と回帰係数の p 値は、この記事のコードをすべて実行して出力を載せています。p 値の分布・人数による変化・p 値のばらつき・有意な結果のうち帰無仮説が正しかった割合・p ハッキングは、乱数の種を固定したシミュレーションの実測値です。p 値の定義と6原則は米国統計学会(ASA)の2016年の声明(プレスリリースと、声明を紹介した論文)、0.05 の由来と 0.005 の提案は英語版 Wikipedia「Statistical significance」、p 値の表記は GraphPad Prism のガイド、関数の仕様は SciPy・statsmodels の公式ドキュメントで確かめました(確認日 2026年10月22日)。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「p値とは|意味・有意水準・よくある誤解をPythonで実演」
p値とは(意味を身近な例で)
この節では、p 値が「何の確率」なのかを、コイン投げの例で分かります。
p 値(p-value)は、帰無仮説(差が無い・効果が無い、という仮説)が正しいと仮定したとき、観測した結果と同じか、それより極端な結果が得られる確率です。 p は probability(確率)の頭文字で、日本語では「有意確率」とも呼ばれます。米国統計学会(ASA)の声明は、p 値を「特定の統計モデルのもとで、データの統計的な要約(例:2群の平均の差)が、観測された値と同じかそれより極端になる確率」と説明しています。
コインを10回投げて9回表が出たら
「このコインは表が出やすいのでは?」を確かめる例です。
帰無仮説を置く
「コインは公平で、表の確率は 1/2」と仮に決めます。言いたいこと(表が出やすい)の反対を置くのがポイントです。
起こりうる結果の確率を出す
公平なコインを10回投げると、表と裏の出方は 2の10乗 = 1,024 通りで、どれも同じ確率です。9回表になるのは10通り、10回表は1通りです。
今回以上に極端な確率を足す
「9回以上表」は 10 + 1 = 11 通りなので、11 ÷ 1,024 = 0.0107。これが p 値(片側)です。
有意水準と比べる
0.0107 は 0.05 より小さいので、「公平なコインなら約1%しか起きないことが起きた」と考え、帰無仮説を棄却します。
公平なコインで、表が出る回数ごとの確率を棒にしました。色の濃い棒が「9回以上表」と、その反対側の「1回以下表」です。
p 値は「この1回の結果が出る確率」ではなく、「この結果か、もっと極端な結果が出る確率」です。 9回ちょうどの確率(10/1,024)ではなく、9回と10回の確率を足します。どちら向きの「極端」まで含めるかで、片側と両側に分かれます(後の節)。
同じ計算を Python で行いました。
"""コインを10回投げて9回表:p値を手計算とSciPyで"""
from math import comb
from scipy.stats import binom, binomtest
n = 10
for k in (9, 8):
upper = sum(comb(n, i) for i in range(k, n + 1)) # k回以上表
lower = sum(comb(n, i) for i in range(0, n - k + 1)) # 反対側(n-k回以下表)
print(f"{k}回表: 片側 p = {upper}/1024 = {upper / 1024:.4f} 両側 p = {upper + lower}/1024 = {(upper + lower) / 1024:.4f}")
print(" binom.sf :", round(binom.sf(k - 1, n, 0.5), 4))
print(" binomtest 片側 :", round(binomtest(k, n, 0.5, alternative="greater").pvalue, 4))
print(" binomtest 両側 :", round(binomtest(k, n, 0.5).pvalue, 4))
9回表: 片側 p = 11/1024 = 0.0107 両側 p = 22/1024 = 0.0215
binom.sf : 0.0107
binomtest 片側 : 0.0107
binomtest 両側 : 0.0215
8回表: 片側 p = 56/1024 = 0.0547 両側 p = 112/1024 = 0.1094
binom.sf : 0.0547
binomtest 片側 : 0.0547
binomtest 両側 : 0.1094
9回表なら両側でも p = 0.0215 で 0.05 未満、8回表なら両側 p = 0.109 で有意ではありません。 8回表でも「表が出やすいコイン」かもしれませんが、10回では公平なコインでも約1割の確率で起きる偏りなので、区別できない、という意味です。
帰無仮説と対立仮説(p値の前提)
この節では、p 値を計算するときに必ず置く2つの仮説と、なぜ「否定したい側」を置くのかが分かります。
帰無仮説 H0(きむかせつ)
「差は無い」「効果は無い」「関係は無い」
p 値はこの仮説が正しいとして計算する
例:新版と旧版の応答時間の平均は同じ
対立仮説 H1
「差がある」「効果がある」
本当に言いたいことはふつうこちら
例:新版と旧版の平均は違う(両側)/新版のほうが速い(片側)
「差が無い」と仮定すると、偶然でどれくらいの差が出るかを計算できます。 「差がある」と仮定しても、差の大きさが決まらないので確率を計算できません。そこで帰無仮説を置き、その仮説のもとでは珍しすぎる結果が出たら「帰無仮説は合わない」と判断します。背理法に似た考え方です。
帰無(null)は「無に帰したい」という意味で、捨てたい側の仮説だから、この名前があります。
有意水準と有意差(0.05の意味と由来)
この節では、有意水準 0.05 の意味、有意差の判定のしかた、2種類の誤りが分かります。
有意水準(α、アルファ)は、「p 値がこれより小さければ有意とする」と前もって決める基準で、多くの分野で 0.05(5%)が使われます。 p 値が有意水準より小さいとき「統計的に有意」「有意差あり」と言います。有意水準は「帰無仮説が正しいのに棄却してしまう確率」の上限でもあり、「危険率」とも呼ばれます。
| 用語 | 意味 | 決めるとき |
|---|---|---|
| 有意水準 α | 帰無仮説を棄却する基準(0.05 など) | データを見る前に決める |
| p 値(有意確率) | データから計算した確率 | データを見た後に出る |
| 有意差あり | p 値 < 有意水準 | 判定の結果 |
| 危険率 | 有意水準と同じ意味で使われることが多い | ― |
0.05 はなぜ?
英語版 Wikipedia「Statistical significance」によると、フィッシャー(Ronald Fisher)が1925年の著書『Statistical Methods for Research Workers』で、帰無仮説を棄却する便利な目安として「20回に1回(0.05)」を示したのが始まりです。フィッシャー自身は 0.05 を固定の基準とは考えておらず、1956年には状況に応じて有意水準を決めることを勧めています。2017年には72人の著者が、再現性を高めるため基準を 0.005 に下げる提案をしました(Benjamin ほか、2018年掲載)。基準を厳しくすると偽陰性が増えるなどの反論もあり、分野によって 0.01 や 0.001 を使うこともあります。
有意差の判定で起きる2種類の誤り
| 本当は差が無い(H0 が正しい) | 本当は差がある(H1 が正しい) | |
|---|---|---|
| p < α(有意と判定) | 第1種の誤り(偽陽性)。確率は α | 正しい判定。確率は検出力 1 − β |
| p ≥ α(有意でないと判定) | 正しい判定 | 第2種の誤り(偽陰性)。確率は β |
有意水準を 0.05 にすると、本当は差が無いときに「有意」と判定してしまう確率が5%になります。 後のシミュレーションでは、差の無い2群を1万回比べて 4.72% が p < 0.05 でした。差があるのに見逃す確率(β)は人数で決まり、人数が少ないと大きくなります。
p値の求め方(t値・z値から確率へ)
この節では、p 値を計算する手順と、t 値・カイ二乗値と p 値の対応が分かります。
p 値は「検定統計量(t 値・z 値・カイ二乗値など)を計算し、帰無仮説のもとでの分布で、その値より外側にある面積を求める」という手順で出します。 コイン投げは結果の数が少ないので全部数えられましたが、ふつうはこの手順です。
flowchart TD
A[データ] --> B[検定統計量を計算<br>t = 差 ÷ 標準誤差]
B --> C[帰無仮説のもとでの分布<br>t 分布・正規分布など]
C --> D[統計量より外側の面積<br>= p 値]
t 値(z 値)の大きさと両側の p 値の対応です。自由度20の t 分布と、標準正規分布で計算しました。
from scipy import stats
print("|t| または |z| p(df=20) p(正規)")
for tv in (1.0, 1.645, 1.96, 2.0, 2.086, 2.576, 3.0, 3.29):
print(f"{tv:>6.3f} {2 * stats.t.sf(tv, 20):.4f} {2 * stats.norm.sf(tv):.4f}")
print("両側5%の境界: t(df=20) =", round(stats.t.ppf(0.975, 20), 3), " z =", round(stats.norm.ppf(0.975), 3))
|t| または |z| p(df=20) p(正規)
1.000 0.3293 0.3173
1.645 0.1156 0.1000
1.960 0.0641 0.0500
2.000 0.0593 0.0455
2.086 0.0500 0.0370
2.576 0.0180 0.0100
3.000 0.0071 0.0027
3.290 0.0037 0.0010
両側5%の境界: t(df=20) = 2.086 z = 1.96
t 値(z 値)の絶対値が大きいほど、p 値は小さくなります。 正規分布では |z| = 1.96 がちょうど p = 0.05 です。t 分布は裾が厚いので、自由度20では |t| = 2.086 で p = 0.05 になります。sf は「その値より上の確率(1 − 累積分布関数)」で、両側なので2倍しています。
片側検定と両側検定の違い
この節では、片側と両側で p 値がどう変わるか、どちらを使うかが分かります。
コイン10回で9回表のとき
左右対称の分布では、片側の p 値は両側の半分になる
| 使い方 | 対立仮説の例 | 選ぶ場面 |
|---|---|---|
| 両側検定 | 新版と旧版の平均は違う | 上か下か分からないとき。論文・レポートの基本 |
| 片側検定 | 新版のほうが平均が小さい | 逆向きの差が起きても判断が同じで、向きをデータを見る前に決めたとき |
片側検定は p 値が半分になるので、データを見てから「有意にしたいので片側にする」のは p ハッキングの一種です。 向きは事前に決めます。SciPy では alternative="two-sided"(既定)・"greater"・"less" で指定します。向きを逆に指定すると、後の t 検定の例のように p = 0.98 のような大きな値になります。
Pythonでp値を計算する(t検定)
この節では、2つのグループの平均の差の p 値を、手計算と SciPy の ttest_ind で出し、結果の読み方が分かります。
例として、API の応答時間(ミリ秒)を旧版と新版で12回ずつ測った値を比べます。
"""t検定でp値を求める:APIの応答時間(ミリ秒)を旧版と新版で比べる"""
import math
import numpy as np
from scipy import stats
old = np.array([212, 198, 225, 240, 205, 219, 231, 208, 226, 215, 237, 202])
new = np.array([204, 216, 197, 223, 201, 210, 195, 219, 208, 192, 214, 205])
print(f"旧版 平均 {old.mean():.2f} 標準偏差 {old.std(ddof=1):.2f} n={old.size}")
print(f"新版 平均 {new.mean():.2f} 標準偏差 {new.std(ddof=1):.2f} n={new.size}")
# 手計算(Welch の t 検定)
va, vb = old.var(ddof=1) / old.size, new.var(ddof=1) / new.size
se = math.sqrt(va + vb)
t = (old.mean() - new.mean()) / se
df = (va + vb) ** 2 / (va ** 2 / (old.size - 1) + vb ** 2 / (new.size - 1))
p = 2 * stats.t.sf(abs(t), df)
print(f"\n手計算 Welch: 差 {old.mean() - new.mean():.2f} SE {se:.4f} t {t:.4f} 自由度 {df:.2f} p {p:.6f}")
r = stats.ttest_ind(old, new, equal_var=False)
print(f"ttest_ind(equal_var=False): t={r.statistic:.4f} p={r.pvalue:.6f} df={r.df:.2f}")
ci = r.confidence_interval(0.95)
print(f" 差の95%信頼区間: {ci.low:.2f} 〜 {ci.high:.2f} ms")
r2 = stats.ttest_ind(old, new)
print(f"ttest_ind(既定 equal_var=True, Student): t={r2.statistic:.4f} p={r2.pvalue:.6f} df={r2.df:.0f}")
r3 = stats.ttest_ind(old, new, equal_var=False, alternative="greater")
print(f"片側(旧版 > 新版): p={r3.pvalue:.6f}")
r4 = stats.ttest_ind(old, new, equal_var=False, alternative="less")
print(f"片側(旧版 < 新版): p={r4.pvalue:.6f}")
# 効果量 Cohen の d(プールした標準偏差)
sp = math.sqrt(((old.size - 1) * old.var(ddof=1) + (new.size - 1) * new.var(ddof=1)) / (old.size + new.size - 2))
print(f"Cohen の d = {(old.mean() - new.mean()) / sp:.3f}")
# 対応のある t 検定(同じ12個のエンドポイントを改修の前後で測った、と読み替えた場合)
rp = stats.ttest_rel(old, new)
print(f"\nttest_rel(対応あり): t={rp.statistic:.4f} p={rp.pvalue:.6f} df={rp.df}")
u = stats.mannwhitneyu(old, new)
print(f"Mann-Whitney U: U={u.statistic:.1f} p={u.pvalue:.6f}")
旧版 平均 218.17 標準偏差 13.81 n=12
新版 平均 207.00 標準偏差 9.81 n=12
手計算 Welch: 差 11.17 SE 4.8894 t 2.2838 自由度 19.85 p 0.033538
ttest_ind(equal_var=False): t=2.2838 p=0.033538 df=19.85
差の95%信頼区間: 0.96 〜 21.37 ms
ttest_ind(既定 equal_var=True, Student): t=2.2838 p=0.032396 df=22
片側(旧版 > 新版): p=0.016769
片側(旧版 < 新版): p=0.983231
Cohen の d = 0.932
ttest_rel(対応あり): t=2.3949 p=0.035549 df=11
Mann-Whitney U: U=106.5 p=0.049499
手計算の部分を式で書くと、次のとおりです。
標準誤差 SE = √( 旧版の分散 ÷ 12 + 新版の分散 ÷ 12 ) = √( 13.81² ÷ 12 + 9.81² ÷ 12 ) = 4.889
t 値 t = 平均の差 ÷ SE = 11.17 ÷ 4.889 = 2.284
自由度 Welch–Satterthwaite の式で 19.85
p 値(両側)p = 2 × (自由度 19.85 の t 分布で 2.284 より外側の確率) = 0.0335
p = 0.0335 で 0.05 より小さいので、「旧版と新版の平均応答時間には有意差がある」と判定できます。 読み取れることを表にしました。
| 結果 | 読み方 |
|---|---|
手計算と ttest_ind(equal_var=False) が一致 |
p = 0.033538。SciPy の中身は上の式と同じ |
既定の ttest_ind は p = 0.0324 |
既定は equal_var=True(Student の t 検定)。分散が違ってよい Welch のほうが安全 |
| 片側(旧版 > 新版)は p = 0.0168 | 両側の半分。向きを逆にすると p = 0.983 |
| 差の95%信頼区間は 0.96〜21.37 ms | 0 を含まないので有意。速くなった幅は約1〜21 ms と幅がある |
| Cohen の d = 0.93 | 効果量。p 値とは別に「差の大きさ」を表す |
| 対応のある t 検定は p = 0.0355 | 同じ対象を前後で測ったときに使う。データの取り方で検定が変わる |
| Mann-Whitney は p = 0.0495 | 順位で比べる方法。外れ値に強いが、検出力は少し下がる |
どの検定を使うか
flowchart TD
A{比べるものは?} -->|平均| B{同じ対象を<br>2回測った?}
A -->|割合| C[カイ二乗検定<br>少数なら<br>フィッシャー]
B -->|はい| D[対応のある<br>t 検定]
B -->|いいえ| E[Welch の<br>t 検定]
| データ | 検定 | SciPy の関数 |
|---|---|---|
| 2群の平均(別々の人) | Welch の t 検定 | ttest_ind(a, b, equal_var=False) |
| 同じ人の前後 | 対応のある t 検定 | ttest_rel(before, after) |
| 順位で比べたい・外れ値が多い | Mann-Whitney の U 検定 | mannwhitneyu(a, b) |
| 3群以上の平均 | 一元配置分散分析 | f_oneway(a, b, c) |
| 割合の表(2×2 など) | カイ二乗検定・フィッシャーの正確検定 | chi2_contingency(t)・fisher_exact(t) |
| 回数が理論どおりか | 適合度検定・二項検定 | chisquare(obs)・binomtest(k, n) |
| 2つの量の関係 | 相関係数の検定 | pearsonr(x, y)・spearmanr(x, y) |
カイ二乗検定・相関・回帰のp値
この節では、割合の差・相関係数・回帰係数の p 値を Python で出す方法と、補正の有無で p 値が変わる例が分かります。
"""カイ二乗検定・相関・回帰の p 値"""
import numpy as np
from scipy import stats
import statsmodels.api as sm
# 1) カイ二乗検定:旧版と新版で、エラーになったリクエストの数
table = np.array([[30, 970], # 旧版: エラー 30 / 正常 970
[15, 985]]) # 新版: エラー 15 / 正常 985
r = stats.chi2_contingency(table, correction=False)
print(f"カイ二乗(補正なし): chi2={r.statistic:.4f} 自由度={r.dof} p={r.pvalue:.6f}")
print("期待度数:", r.expected_freq.round(1).tolist())
ry = stats.chi2_contingency(table)
print(f"カイ二乗(既定・Yates補正): chi2={ry.statistic:.4f} p={ry.pvalue:.6f}")
print(f"フィッシャーの正確検定: p={stats.fisher_exact(table).pvalue:.6f}")
exp = table.sum(1, keepdims=True) * table.sum(0) / table.sum() # 手計算
chi2 = ((table - exp) ** 2 / exp).sum()
print(f"手計算: chi2={chi2:.4f} p=chi2.sf(chi2, 1)={stats.chi2.sf(chi2, 1):.6f}")
# 2) 適合度検定:サイコロ 120 回
obs = [28, 15, 22, 17, 24, 14]
g = stats.chisquare(obs)
print(f"\nサイコロ120回 {obs}: chi2={g.statistic:.3f} p={g.pvalue:.4f}")
# 3) 相関係数の p 値
x = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # 1日の勉強時間(例)
y = np.array([52, 55, 61, 58, 66, 63, 70, 68, 75, 73]) # テストの点
pr = stats.pearsonr(x, y)
print(f"\nピアソンの相関: r={pr.statistic:.4f} p={pr.pvalue:.2e}")
ci = pr.confidence_interval(0.95)
print(f" r の95%信頼区間: {ci.low:.3f} 〜 {ci.high:.3f}")
# 4) 回帰係数の p 値(statsmodels の OLS)
res = sm.OLS(y, sm.add_constant(x)).fit()
print()
print(res.summary().tables[1])
print("係数のp値:", [f"{v:.2e}" for v in res.pvalues])
カイ二乗(補正なし): chi2=5.1151 自由度=1 p=0.023719
期待度数: [[22.5, 977.5], [22.5, 977.5]]
カイ二乗(既定・Yates補正): chi2=4.4558 p=0.034783
フィッシャーの正確検定: p=0.033656
手計算: chi2=5.1151 p=chi2.sf(chi2, 1)=0.023719
サイコロ120回 [28, 15, 22, 17, 24, 14]: chi2=7.700 p=0.1736
ピアソンの相関: r=0.9503 p=2.52e-05
r の95%信頼区間: 0.798 〜 0.988
==============================================================================
coef std err t P>|t| [0.025 0.975]
------------------------------------------------------------------------------
const 50.8667 1.730 29.406 0.000 46.878 54.856
x1 2.4061 0.279 8.630 0.000 1.763 3.049
==============================================================================
係数のp値: ['1.94e-09', '2.52e-05']
| 結果 | 読み方 |
|---|---|
| エラー率 3.0% と 1.5%:補正なし p = 0.0237 | 期待度数は各セル 22.5 と 977.5。(30 − 22.5)² ÷ 22.5 などを4つ足して 5.1151 |
| 同じ表で既定(Yates 補正)は p = 0.0348 | SciPy の chi2_contingency は自由度1のとき既定で補正する。どちらを使ったか書く |
| フィッシャーの正確検定は p = 0.0337 | 近似を使わない計算。期待度数が5未満のセルがあるときに使う |
| サイコロは p = 0.174 | 120回で 28 回と 14 回の差があっても、偏りがあるとは言えない |
| 相関 r = 0.95、p = 2.52e-05 | 「相関が0」という帰無仮説の検定。相関の強さは r と区間で見る |
| 回帰の傾き 2.41 の P>|t| は 2.52e-05 | 説明変数が1つの回帰の傾きの p 値は、相関係数の p 値と同じ |
statsmodels の表の P>|t| が回帰係数の p 値で、「この係数は0(関係が無い)」という帰無仮説の検定です。0.000 と表示されていても p が0なのではなく、小さすぎて表示の桁に入らないだけです(定数項は 1.94e-09)。回帰そのものの計算は、関連記事「最小二乗法とは|公式・手計算の例とPythonでの求め方を実例で解説」で扱っています。ABテストのように2つの割合(CVR)を比べる検定と、必要な人数の計算は、関連記事「ABテストとは|やり方・サンプルサイズ・有意差の判定をPythonで実演」で扱っています。
p値の書き方・読み方(p<0.001・アスタリスク)
この節では、論文やレポートで p 値をどう書くか、表のアスタリスクの読み方が分かります。
| 書き方 | 例 | 注意 |
|---|---|---|
| 値をそのまま書く | p = 0.034 | 「p < 0.05」だけより情報が多い。ASA の声明も完全な報告を求めている |
| とても小さいとき | p < 0.001 | 0 とは書かない。p 値はちょうど0にはならない |
| 検定統計量と一緒に | t(19.85) = 2.28, p = 0.034 | 自由度・統計量・検定の名前を書くと、読む人が確かめられる |
| 区間と効果量も | 差 11.2 ms(95%CI 1.0〜21.4), d = 0.93 | 差の大きさが伝わる |
| アスタリスク | * p<0.05、** p<0.01、*** p<0.001 | よく使われる記号。意味は図表の注で定義する |
GraphPad Prism のガイドでは、APA(米国心理学会)形式は先頭の0を省いた3桁(.123)で「< .001」、NEJM 形式は0を付けた3桁、GraphPad 形式は4桁で p < 0.0001 を四つのアスタリスクで表す、と説明されています。アスタリスクの区切りは分野・ツールで違うので、表の下に「* p<0.05」などの注を付けます。 p = 0.051 を「有意傾向」と書く例もありますが、0.05 の前後で証拠の強さが急に変わるわけではないので、値と区間をそのまま示すほうが誤解を生みません。
p値のよくある誤解(米国統計学会の6原則)
この節では、p 値について間違えやすい点を、米国統計学会(ASA)の声明と実際の計算で確かめられます。
米国統計学会は2016年3月7日、p 値の誤用を受けて「統計的有意性と P 値に関する声明」を出し、6つの原則を示しました。
| 番号 | ASA の原則(要約) | この記事で確かめた例 |
|---|---|---|
| 1 | p 値は、データが特定の統計モデルとどれだけ合わないかを示せる | p が小さいほど、帰無仮説とデータが合わない |
| 2 | p 値は、仮説が正しい確率でも、データが偶然だけで生じた確率でもない | 有意な結果の47.5%が帰無仮説どおり(後の節) |
| 3 | 結論や判断は、p 値がある閾値を越えたかだけで決めるべきではない | p = 0.034 でも区間は 1〜21 ms と幅広い |
| 4 | 正しい推論には、完全な報告と透明性が要る | 試した分析を全部書かないと p ハッキングになる |
| 5 | p 値や有意性は、効果の大きさや結果の重要さを測らない | d = 0.02 の小さな差でも各群10万人で p = 7.75e-06 |
| 6 | p 値だけでは、モデルや仮説についての証拠のよい尺度にならない | 区間・効果量・事前の確からしさと合わせて読む |
よく見る誤解と、正しい読み方です。
- 1誤:p = 0.03 なら帰無仮説が正しい確率は3%正:p 値は帰無仮説が正しいと「仮定して」計算した確率。仮説が正しい確率ではない(原則2)
- 2誤:p = 0.03 なら結果が偶然である確率は3%正:これも原則2で否定されている読み方。偶然かどうかの確率は p 値からは出ない
- 3誤:p 値が小さいほど効果が大きい正:p 値は人数で大きく変わる。効果の大きさは差・効果量・信頼区間で見る(原則5)
- 4誤:p > 0.05 なので差が無いことが分かった正:「差があるとは言えない」だけ。人数が少なければ、差があっても有意になりにくい
- 5誤:1 − p が対立仮説の正しい確率(p=0.03 なら97%)正:そうした確率を出したいなら、ベイズの方法で事後確率を計算する
- 6誤:同じ実験をやり直しても、ほぼ同じ p 値になる正:同じ条件の10回で p は 0.0002〜0.74 に散らばった(後の節)
- 7誤:p = 0.049 と p = 0.051 は結論が正反対正:証拠の強さはほとんど同じ。閾値だけで判断しない(原則3)
2019年には学術誌『The American Statistician』が p < 0.05 の先を考える特集号を出し、「統計的に有意」という言い方をやめることや、不確かさを受け入れる・よく考える・開かれている・謙虚である(ATOM)という姿勢を勧めています。p 値を使わない、ということではなく、p 値だけで白黒を決めない、という流れです。
シミュレーションで見るp値の分布(帰無仮説が正しいと一様分布)
この節では、帰無仮説が正しいとき p 値は0〜1に均等に散らばり、差があるときは0の近くに集まることが、数値で分かります。
差の無い2群(どちらも平均0・標準偏差1、各20人)を1万回 t 検定し、p 値を0.1刻みで数えました。 差がある場合(効果量 d = 0.5 と 1.0)も同じように数えています。
"""シミュレーション:帰無仮説が正しいとき・差があるときの p 値の分布"""
import numpy as np
from scipy import stats
rng = np.random.default_rng(343)
SIMS, n = 10000, 20
def pvals(delta):
a = rng.normal(0, 1, (SIMS, n))
b = rng.normal(delta, 1, (SIMS, n))
return stats.ttest_ind(a, b, axis=1).pvalue # 1万回分を一度に検定
bins = np.linspace(0, 1, 11)
for delta, label in ((0.0, "差なし(帰無仮説が正しい)"), (0.5, "差あり d=0.5"), (1.0, "差あり d=1.0")):
p = pvals(delta)
h, _ = np.histogram(p, bins)
print(f"\n{label} 1万回・各群{n}人")
for lo, c in zip(bins[:-1], h):
print(f" {lo:.1f}〜{lo + 0.1:.1f}: {c / SIMS:6.2%}")
print(f" p<0.05 の割合: {(p < 0.05).mean():.2%} p<0.01: {(p < 0.01).mean():.2%} p<0.001: {(p < 0.001).mean():.2%}")
print(f" p の中央値: {np.median(p):.4f}")
差なし(帰無仮説が正しい) 1万回・各群20人
0.0〜0.1: 9.44%
0.1〜0.2: 10.00%
0.2〜0.3: 10.05%
0.3〜0.4: 10.54%
0.4〜0.5: 10.01%
0.5〜0.6: 9.69%
0.6〜0.7: 10.35%
0.7〜0.8: 9.86%
0.8〜0.9: 10.19%
0.9〜1.0: 9.87%
p<0.05 の割合: 4.72% p<0.01: 0.87% p<0.001: 0.08%
p の中央値: 0.4996
差あり d=0.5 1万回・各群20人
0.0〜0.1: 46.05%
0.1〜0.2: 15.36%
0.2〜0.3: 8.85%
0.3〜0.4: 7.12%
0.4〜0.5: 5.60%
0.5〜0.6: 4.17%
0.6〜0.7: 3.31%
0.7〜0.8: 3.60%
0.8〜0.9: 3.20%
0.9〜1.0: 2.74%
p<0.05 の割合: 33.48% p<0.01: 14.23% p<0.001: 3.37%
p の中央値: 0.1206
差あり d=1.0 1万回・各群20人
0.0〜0.1: 92.51%
...(0.1 以上は合計 7.49%)
p<0.05 の割合: 86.73% p<0.01: 66.99% p<0.001: 36.29%
p の中央値: 0.0030
帰無仮説が正しいとき、p 値はどの区間にもほぼ10%ずつ入りました(一様分布)。 そのため p < 0.05 になる割合は約5%(4.72%)、p < 0.01 は約1%(0.87%)で、有意水準がそのまま偽陽性の割合になります。p 値の中央値も 0.4996 で、「差が無いなら p は 0.5 前後が普通、0.05 未満になるのは20回に1回」という意味です。
差があるときは p 値が0の近くに集まりますが、d = 0.5・各群20人では p < 0.05 は 33.48% だけでした。 本当に差があっても、3回に2回は「有意ではない」になる人数です。この割合が検出力で、statsmodels の計算(0.338)とも一致しました。d = 1.0 では 86.73% が p < 0.05 でした。
サンプルサイズでp値が変わる(同じ差でも人数で有意になる)
この節では、差の大きさが同じでも人数で p 値が大きく変わること、p 値が実験ごとにばらつくことが分かります。
平均が 52 と 50(差2点、標準偏差10、効果量 d = 0.2)という同じ結果を、各群の人数だけ変えて t 検定しました。
"""サンプルサイズと p 値、p 値のばらつき"""
import numpy as np
from scipy import stats
from statsmodels.stats.power import TTestIndPower
print("各群の人数 t 値 p 値 差の95%信頼区間")
for n in (10, 50, 100, 200, 400, 1000, 10000):
r = stats.ttest_ind_from_stats(52, 10, n, 50, 10, n) # 平均・標準偏差・人数から検定
se = 10 * np.sqrt(2 / n); q = stats.t.ppf(0.975, 2 * n - 2)
print(f"{n:>9,d} {r.statistic:6.3f} {r.pvalue:.2e} {2 - q * se:+.2f} 〜 {2 + q * se:+.2f}")
for n in (1000, 100000, 1000000): # とても小さい差(d=0.02)
r = stats.ttest_ind_from_stats(50.2, 10, n, 50, 10, n)
print(f"d=0.02 各群 {n:>9,d}人: p={r.pvalue:.2e}")
pw = TTestIndPower()
for d in (0.2, 0.5, 1.0):
print(f"d={d}: 各群20人の検出力 {pw.power(d, nobs1=20, alpha=0.05):.3f} "
f"80%に要る各群の人数 {int(np.ceil(pw.solve_power(d, power=0.8, alpha=0.05)))}")
rng = np.random.default_rng(7) # 同じ条件の実験を10回
ps = []
for i in range(10):
a = rng.normal(0, 1, 30); b = rng.normal(0.5, 1, 30)
ps.append(stats.ttest_ind(b, a).pvalue)
print("\n同じ実験10回の p 値:", " ".join(f"{p:.4f}" for p in ps))
print(f"検出力(d=0.5・各群30人): {pw.power(0.5, nobs1=30, alpha=0.05):.3f}")
各群の人数 t 値 p 値 差の95%信頼区間
10 0.447 6.60e-01 -7.40 〜 +11.40
50 1.000 3.20e-01 -1.97 〜 +5.97
100 1.414 1.59e-01 -0.79 〜 +4.79
200 2.000 4.62e-02 +0.03 〜 +3.97
400 2.828 4.79e-03 +0.61 〜 +3.39
1,000 4.472 8.18e-06 +1.12 〜 +2.88
10,000 14.142 3.45e-45 +1.72 〜 +2.28
d=0.02 各群 1,000人: p=6.55e-01
d=0.02 各群 100,000人: p=7.75e-06
d=0.02 各群 1,000,000人: p=2.10e-45
d=0.2: 各群20人の検出力 0.095 80%に要る各群の人数 394
d=0.5: 各群20人の検出力 0.338 80%に要る各群の人数 64
d=1.0: 各群20人の検出力 0.869 80%に要る各群の人数 17
同じ実験10回の p 値: 0.0002 0.0382 0.0764 0.7432 0.0025 0.0447 0.0651 0.0933 0.0340 0.0217
検出力(d=0.5・各群30人): 0.478
差は同じ2点なのに、各群10人では p = 0.66、200人で p = 0.046(有意)、1万人では p = 3.45e-45 になりました。 t 値は人数の平方根に比例して大きくなるので、人数を4倍にすると t 値は2倍です。一方、差の95%信頼区間は人数が増えるほど狭くなり、+1.72〜+2.28 のように「差は約2点」と絞り込まれます。
差が 0.2 点(d = 0.02)というごく小さな差でも、各群10万人なら p = 7.75e-06 で有意になります。 アクセスログや大規模データでは、ほとんど意味の無い差でも p 値は小さくなります。「有意かどうか」より「差がどれくらいか」を見る理由です(原則5)。
同じ条件(d = 0.5・各群30人)の実験を10回くり返すと、p 値は 0.0002 から 0.7432 までばらつき、有意になったのは10回中6回でした。 この条件の検出力は 47.8% なので、本当に差があっても約半分の実験は「有意でない」になります。1回の p 値で「再現した・しなかった」を決めにくいのはこのためです。
p値と信頼区間・効果量の関係
この節では、p 値・信頼区間・効果量がそれぞれ何を表すか、どう一緒に使うかが分かります。
1p 値
帰無仮説(差 = 0)とデータがどれだけ合わないか。差の大きさは分からない。人数が増えると小さくなる。
2信頼区間
差がどの範囲にありそうか。95%区間が0を含まなければ、両側 p < 0.05 と同じ判定になる。
3効果量
差の大きさを、ばらつきで割った値など。Cohen の d は 0.2・0.5・0.8 が小・中・大の目安とされる。人数で変わらない。
p 値と信頼区間は同じ計算の裏表です。 上の t 検定(p = 0.0335)で、信頼度を変えて区間を出しました。
for cl in (0.95, 0.966, 0.99):
ci = r.confidence_interval(cl) # r は上の ttest_ind(old, new, equal_var=False) の結果
print(f"{cl:.1%}信頼区間: {ci.low:+.2f} 〜 {ci.high:+.2f}")
95.0%信頼区間: +0.96 〜 +21.37
96.6%信頼区間: +0.03 〜 +22.30
99.0%信頼区間: -2.76 〜 +25.09
信頼度を 1 − p(96.6%)にすると、区間の端がほぼ0になりました。 95%区間は0を含まない(p < 0.05 で有意)、99%区間は0を含む(p > 0.01 なので有意水準1%では有意でない)と対応しています。区間を出せば p 値の判定もでき、さらに差の大きさも分かるので、レポートには p 値と区間を一緒に載せます。
| 報告に載せるもの | 例(API の応答時間) | 伝わること |
|---|---|---|
| 差 | 11.2 ms 速くなった | どれだけ変わったか |
| 95%信頼区間 | 1.0〜21.4 ms | 差の確かさ(幅が広い=まだ不確か) |
| 効果量 | d = 0.93 | ばらつきに対する差の大きさ |
| p 値 | p = 0.034(Welch の t 検定) | 差が0という仮説とどれだけ合わないか |
| 人数 | 各12回 | 結果の確かさの土台 |
p値の落とし穴:有意な結果のうち帰無仮説が正しい割合
この節では、「p < 0.05 なら誤りは5%」とは言えない理由が、数値で分かります。
試す仮説のうち本当に効果があるものが10%しかないとき、p < 0.05 になった結果のうち約半分は、本当は効果が無いものでした。 10万個の仮説を、各群30人の t 検定で調べたシミュレーションです(効果があるときは d = 0.5)。
# 前の節のコードの続き(numpy・scipy.stats を読み込み済み)
rng = np.random.default_rng(343)
SIMS = 100000
for share_true, n in ((0.1, 30), (0.5, 30), (0.1, 100)):
has = rng.random(SIMS) < share_true # 本当に効果がある仮説の割合
a = rng.normal(0, 1, (SIMS, n)); b = rng.normal(np.where(has, 0.5, 0.0)[:, None], 1, (SIMS, n))
sig = stats.ttest_ind(b, a, axis=1).pvalue < 0.05
print(f"効果がある仮説 {share_true:.0%}・各群{n}人: 有意 {sig.sum():,d} 件のうち"
f"帰無仮説が正しかった割合 {(~has & sig).sum() / sig.sum():.1%}")
効果がある仮説 10%・各群30人: 有意 9,353 件のうち帰無仮説が正しかった割合 47.5%
効果がある仮説 50%・各群30人: 有意 26,127 件のうち帰無仮説が正しかった割合 9.5%
効果がある仮説 10%・各群100人: 有意 13,821 件のうち帰無仮説が正しかった割合 32.9%
有意水準5%は「効果が無いものを有意と判定する割合」であり、「有意と判定したものが誤りである割合」ではありません。 後者は、もともと効果がある仮説がどれだけあるか(事前の確からしさ)と、検出力で決まります。当たりの少ない探索(たくさんの施策や指標を試す)では、有意な結果の中に偶然のものが多く混ざります。p 値が「仮説が正しい確率ではない」(原則2)ことの具体例です。
pハッキング(p値を小さくする操作)
この節では、p ハッキングとは何か、どの操作で偽陽性がどれだけ増えるかが分かります。
p ハッキングは、分析のやり方を何通りも試して、p < 0.05 になったものだけを報告することです。 データの掘り返し(data dredging)とも呼ばれます。1つ1つは自然に見える操作でも、組み合わせると偽陽性が大きく増えます。本当は差が無い2群で、よくある4つの操作を試したシミュレーションです。
"""p ハッキング:本当は差が無いのに、やり方を変えて何度も試すと「有意」が増える"""
import numpy as np
from scipy import stats
rng = np.random.default_rng(343)
SIMS = 5000
def run(n=20, outcomes=1, peek=False, outlier=False, covar=False):
hits = 0
for _ in range(SIMS):
found = False
cov = np.full((outcomes, outcomes), 0.5) + np.eye(outcomes) * 0.5 # 相関 0.5 の指標
nmax = 50 if peek else n
a = rng.multivariate_normal(np.zeros(outcomes), cov, nmax)
b = rng.multivariate_normal(np.zeros(outcomes), cov, nmax)
sizes = range(n, nmax + 1, 10) if peek else [n]
for m in sizes: # 途中で見る:20人から10人ずつ足して50人まで
for k in range(outcomes):
x, y = a[:m, k], b[:m, k]
tries = [(x, y)]
if outlier: # 平均±2SD の外を除いた版も試す
sx, sy = x.std(ddof=1), y.std(ddof=1)
tries.append((x[np.abs(x - x.mean()) < 2 * sx], y[np.abs(y - y.mean()) < 2 * sy]))
for xx, yy in tries:
ps = [stats.ttest_ind(xx, yy).pvalue]
if covar: # 検定の種類を変えて試す
ps += [stats.ttest_ind(xx, yy, equal_var=False).pvalue, stats.mannwhitneyu(xx, yy).pvalue]
if min(ps) < 0.05:
found = True
if found:
break
hits += found
return hits / SIMS
rows = [
("決めたとおり1回だけ検定", {}),
("指標を3つ見て、どれか有意なら報告", {"outcomes": 3}),
("20人で見て、有意でなければ10人ずつ足す(最大50人)", {"peek": True}),
("外れ値を除く・除かないの両方を試す", {"outlier": True}),
("t検定・Welch・Mann-Whitney を試す", {"covar": True}),
("上の4つを全部", {"outcomes": 3, "peek": True, "outlier": True, "covar": True}),
]
print(f"本当は差が無い2群(各20人〜)を {SIMS:,d} 回。有意水準 5%")
for label, kw in rows:
print(f"{run(**kw):6.2%} {label}")
本当は差が無い2群(各20人〜)を 5,000 回。有意水準 5%
4.70% 決めたとおり1回だけ検定
12.30% 指標を3つ見て、どれか有意なら報告
11.30% 20人で見て、有意でなければ10人ずつ足す(最大50人)
10.60% 外れ値を除く・除かないの両方を試す
6.56% t検定・Welch・Mann-Whitney を試す
52.48% 上の4つを全部
1つずつなら6〜12%でも、4つを組み合わせると、差が無いのに半分以上(52.48%)が「有意」になりました。 1回だけ決めたとおりに検定すれば 4.70% で、有意水準どおりです。どの操作も「分析の自由度」を増やし、その中から都合のよい結果を選べるようにしています。
| p ハッキングの例 | 防ぎ方 |
|---|---|
| 有意になるまで人数を足す・途中で止める | 人数と終了の条件を先に決める。途中で見るなら境界を厳しくする |
| 指標・グループ・期間を後から選ぶ | 主要な指標を1つ先に決める。複数なら多重比較の補正(Bonferroni・Holm 等) |
| 外れ値の除き方・検定の種類を結果を見て決める | 除く基準と検定を分析の前に書いておく |
| データを見てから片側検定にする | 向きは事前に決める。迷ったら両側 |
| 有意な結果だけを報告する | 試した分析を全部書く(ASA の原則4)。事前登録 |
防ぐ基本は「分析の計画を、データを見る前に書いて残す」ことです。 研究では事前登録(プレレジストレーション)と呼ばれます。途中で見る問題・多重比較の補正の計算は、関連記事「ABテストとは|やり方・サンプルサイズ・有意差の判定をPythonで実演」でシミュレーションつきで扱っています。
有意差が出なかったとき(p > 0.05 の読み方)
この節では、p 値が 0.05 を超えたときに、何を確かめて何を結論にするかが分かります。
p > 0.05 は「差があるとは言えない」であって、「差が無い」ではありません。 次の順で確かめます。
信頼区間の幅を見る
区間が狭く0の近くなら「あっても小さい差」。区間が広く大きな差も含むなら「判定できていない」。
検出力を計算する
見つけたい差に対して人数が足りていたか。d = 0.5 を各群20人で調べた検出力は 0.338 で、差があっても3回に2回は見逃す。
次の人数を決める
検出力80%に要る人数(d = 0.5 なら各群64人)を計算し、計画を書いてから次の実験をする。
結果をそのまま残す
有意でなかった結果も、差・区間・人数と一緒に記録する。有意な結果だけが残ると、後で見たとき効果を大きく見積もる。
「差が無いこと」を示したいときは、「差が○○以内なら同等とみなす」という幅を先に決め、同等性検定(TOST)を使います。statsmodels には ttost_ind があります。「B が A を上回る確率」のように仮説の確からしさを直接言いたいときは、ベイズの方法を使います。
p値を計算するときのエラーと直し方(SciPy)
この節では、SciPy で p 値を計算するときに出たエラー文と、p 値が nan になる原因を引けます。
| エラー文・症状 | 原因 | 直し方 |
|---|---|---|
ValueError: Array shapes are incompatible for broadcasting. |
ttest_rel に長さの違う配列を渡した |
対応のある検定は、同じ対象の前後を同じ順・同じ長さで渡す |
p 値が nan |
データに NaN(欠損値)が入っている | nan_policy="omit" を付けるか、欠損を先に除く |
p 値が nan と RuntimeWarning: Precision loss occurred in moment calculation due to catastrophic cancellation. … |
2群とも全部同じ値で、分散が0 | データの取り方・桁を確かめる。差が無いことはデータから明らか |
ValueError: The internally computed table of expected frequencies has a zero element at (np.int64(0), np.int64(0)). |
chi2_contingency の表で、ある列が全部0 |
件数が集まるまで待つ。少ない件数はフィッシャーの正確検定 |
ValueError: All values in `observed` must be nonnegative. |
表に負の数がある | 表を [[該当, 非該当], …] の件数で作る |
ValueError: k (11) must not be greater than n (10). |
binomtest で成功回数が試行回数より多い |
k と n の順番と値を確かめる |
r と p が nan と ConstantInputWarning: An input array is constant; the correlation coefficient is not defined. |
pearsonr に全部同じ値の列を渡した |
値が変化する列か確かめる |
| p 値が 0.0 と表示される | 小さすぎて表示の桁に入らない | f"{p:.2e}" で指数表記にする。「p < 0.001」と書く |
| 片側の p 値が 0.98 など大きい | alternative の向きが逆("greater" と "less") |
1番目の引数 − 2番目の引数の向きで指定する |
配列の作り方と欠損値の扱いの基本は、関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。CSV から読み込んだデータをグループごとに分ける方法は、関連記事「pandasの使い方 逆引き81選|pandas 3.0の実行結果つき」で扱っています。p 値の分布をヒストグラムにして見たいときは、関連記事「matplotlibの使い方と日本語文字化け対策|OS別・Colab・3.12対応」で扱っています。
よくある質問
Q. p値とは簡単に言うと何ですか? A. 「差が無い(効果が無い)」と仮定したとき、今回の結果かそれ以上に極端な結果が偶然で出る確率です。小さいほど、その仮定とデータが合わないことを示します。
Q. p値0.05以下(p < 0.05)とはどういう意味ですか? A. 差が無いなら20回に1回未満しか起きない結果が出た、という意味で、有意水準5%なら「有意差あり」と判定します。「差がある確率が95%」という意味ではありません。
Q. p値が小さいほど効果が大きいのですか? A. いいえ。p 値は人数で大きく変わり、差 2点(d = 0.2)は各群10人で p = 0.66、1万人で p = 3.45e-45 でした。効果の大きさは差・信頼区間・効果量で見ます。
Q. p値が大きい(0.05より大きい)ときは差が無いのですか? A. 「差があるとは言えない」だけで、差が無い証明ではありません。信頼区間が広ければ人数が足りず判定できていない状態です。差が無いことを示すには同等性検定を使います。
Q. 有意水準はなぜ0.05なのですか? A. フィッシャーが1925年の著書で「20回に1回」を便利な目安として示したのが始まりです。固定の決まりではなく、分野によって 0.01 や 0.005 を使います。
Q. p値とt値の関係は? A. t 値は「差 ÷ 標準誤差」で、t 分布でその値より外側の面積が p 値です。|t| が大きいほど p 値は小さく、正規分布なら |z| = 1.96 で両側 p = 0.05 です。
Q. p値の求め方は?Pythonでは?
A. 検定統計量を計算し、帰無仮説のもとでの分布で外側の確率を求めます。Python では scipy.stats.ttest_ind(a, b, equal_var=False).pvalue、割合の表なら chi2_contingency(table).pvalue です。
Q. 片側検定と両側検定はどちらを使いますか? A. 基本は両側です。片側の p 値は両側の半分になるので、データを見てから片側に変えると p ハッキングになります。
Q. 有意確率・危険率とp値の違いは? A. 有意確率は p 値の別名です。危険率は有意水準(α)と同じ意味で使われることが多く、データを見る前に決める基準です。
Q. p < 0.001 やアスタリスク(*)はどう書きますか? A. とても小さい p 値は「p < 0.001」と書き、0 とは書きません。* p<0.05、** p<0.01、*** p<0.001 がよく使われますが、区切りは表の注で定義します。
Q. pハッキングとは何ですか? A. 分析のやり方を何通りも試して、有意になったものだけを報告することです。シミュレーションでは、よくある4つの操作を組み合わせると、差が無いのに 52.48% が有意になりました。
Q. p値は英語で何と言いますか? A. p-value です。p は probability(確率)の頭文字で、「statistically significant(統計的に有意)」「significance level(有意水準)」と一緒に使われます。
まとめ
- p 値は、帰無仮説が正しいと仮定したとき、今回以上に極端な結果が出る確率。コイン10回で9回表なら片側 0.0107、両側 0.0215。
- 有意水準(多くは 0.05)はデータを見る前に決める基準。0.05 はフィッシャーが1925年に示した目安。
- 求め方は「検定統計量 → 分布の外側の面積」。SciPy の
ttest_ind・chi2_contingency・binomtestなどで出せる。Welch の t 検定はequal_var=False。 - 帰無仮説が正しいと p 値は一様分布になり、p < 0.05 は約5%(4.72%)。差があると0に寄るが、人数が少ないと見逃す。
- p 値は効果の大きさでも、仮説が正しい確率でもない(ASA の原則2・5)。同じ差でも人数で p は大きく変わる。差・95%信頼区間・効果量と一緒に報告する。
- 分析のやり方を何通りも試すと偽陽性が増える(4つの操作で 52%)。計画を先に書いて残す。
参考・出典
確認日はいずれも 2026年10月22日です。
- American Statistical Association「American Statistical Association Releases Statement on Statistical Significance and P-Values」(2016年3月7日のプレスリリース):https://www.amstat.org/asa/files/pdfs/P-ValueStatement.pdf
- Bangdiwala, S. I.「Understanding Significance and P-Values」Nepal Journal of Epidemiology 6(1), 2016(ASA 声明の定義と6原則の引用):https://pmc.ncbi.nlm.nih.gov/articles/PMC4850233
- 佐藤俊哉「ASA声明と疫学研究におけるP値」計量生物学 38(2), 2018:https://www.jstage.jst.go.jp/article/jjb/38/2/38_109/_article
- Wasserstein, R. L.「Moving to a World Beyond "p < 0.05"」(USCOTS 2019 の講演資料):https://cause.vmhost.psu.edu/cause/sites/default/files/Moving%20to%20a%20World%20Beyond%20p%20less%20than%200.05%20-%20USCOTS%20May%2017%202019.pdf
- Wikipedia「Statistical significance」:https://en.wikipedia.org/wiki/Statistical_significance
- GraphPad Prism 7 Statistics Guide「Decimal formatting of P values」:https://graphpad.com/guides/prism/7/statistics/stat_decimal_formatting_of_p_values.htm
- SciPy「scipy.stats.ttest_ind」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.ttest_ind.html
- SciPy「scipy.stats.chi2_contingency」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.chi2_contingency.html
- SciPy「scipy.stats.binomtest」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.binomtest.html
- SciPy「scipy.stats.pearsonr」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.pearsonr.html
- statsmodels「TTestIndPower」:https://www.statsmodels.org/stable/generated/statsmodels.stats.power.TTestIndPower.html
- statsmodels「OLS」:https://www.statsmodels.org/stable/generated/statsmodels.regression.linear_model.OLS.html
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「p値とは|意味・有意水準・よくある誤解をPythonで実演」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。