結論

p値とは、帰無仮説が正しいとしたとき、観測した結果以上に極端な結果が出る確率です。小さいほど「偶然だけでは説明しにくい」ことを示します。

この記事でわかること

  • コイン10回の手計算と、検定5種のSciPyコード
  • 米国統計学会の6原則と、誤解7つの正しい読み方
  • pハッキングで偽陽性が5%→52%になる実測

2026年10月22日更新|SciPy 1.17.1・statsmodels 0.15.0で計算

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

帰無仮説を置く

「コインは公平で、表の確率は 1/2」と仮に決めます。言いたいこと(表が出やすい)の反対を置くのがポイントです。

表の確率 = 0.5

2

起こりうる結果の確率を出す

公平なコインを10回投げると、表と裏の出方は 2の10乗 = 1,024 通りで、どれも同じ確率です。9回表になるのは10通り、10回表は1通りです。

全部で1,024通り

3

今回以上に極端な確率を足す

「9回以上表」は 10 + 1 = 11 通りなので、11 ÷ 1,024 = 0.0107。これが p 値(片側)です。

p = 0.0107

4

有意水準と比べる

0.0107 は 0.05 より小さいので、「公平なコインなら約1%しか起きないことが起きた」と考え、帰無仮説を棄却します。

0.0107 < 0.05

公平なコインで、表が出る回数ごとの確率を棒にしました。色の濃い棒が「9回以上表」と、その反対側の「1回以下表」です。

公平なコインを10回投げたときの表の回数の確率濃い棒が両側の p 値に入る部分(合計 22/1,024)

0回0.10%
1回0.98%
2回4.39%
3回11.72%
4回20.51%
5回24.61%
6回20.51%
7回11.72%
8回4.39%
9回0.98%
10回0.10%

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回表のとき

片側「表が出やすい」向きだけを極端とみる。9回以上表の確率だけを足して p = 0.0107
→
両側「表に偏る」「裏に偏る」の両方を極端とみる。1回以下表も足して p = 0.0215

左右対称の分布では、片側の 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

差が無い2群を1万回比べたときの p 値の分布0.1刻み。どの区間もほぼ10%(一様分布)

0.0〜0.19.44%
0.1〜0.210.00%
0.2〜0.310.05%
0.3〜0.410.54%
0.4〜0.510.01%
0.5〜0.69.69%
0.6〜0.710.35%
0.7〜0.89.86%
0.8〜0.910.19%
0.9〜1.09.87%

差がある(d=0.5)2群を1万回比べたときの p 値の分布同じ目盛り。0の近くに集まる

0.0〜0.146.05%
0.1〜0.215.36%
0.2〜0.38.85%
0.3〜0.47.12%
0.4〜0.55.60%
0.5〜1.017.02%

帰無仮説が正しいとき、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 でした。

4.72%差が無いのに p<0.05有意水準5%どおり
33.5%d=0.5 で p<0.05各群20人の検出力
0.50差が無いときの p の中央値p は 0.5 前後が普通

サンプルサイズで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つを全部

差が無いのに「有意」になった割合(5,000回)有意水準5%。操作ごと

1回だけ4.70%
検定を変える6.56%
外れ値の扱い10.60%
人数を足す11.30%
指標を3つ12.30%
4つ全部52.48%

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 は「差があるとは言えない」であって、「差が無い」ではありません。 次の順で確かめます。

1

信頼区間の幅を見る

区間が狭く0の近くなら「あっても小さい差」。区間が広く大きな差も含むなら「判定できていない」。

まず区間

2

検出力を計算する

見つけたい差に対して人数が足りていたか。d = 0.5 を各群20人で調べた検出力は 0.338 で、差があっても3回に2回は見逃す。

TTestIndPower

3

次の人数を決める

検出力80%に要る人数(d = 0.5 なら各群64人)を計算し、計画を書いてから次の実験をする。

後から足さない

4

結果をそのまま残す

有意でなかった結果も、差・区間・人数と一緒に記録する。有意な結果だけが残ると、後で見たとき効果を大きく見積もる。

報告の偏りを防ぐ

「差が無いこと」を示したいときは、「差が○○以内なら同等とみなす」という幅を先に決め、同等性検定(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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?