結論

確率密度関数(pdf)は、連続な値の「出やすさの密度」を表す関数で、確率はグラフの下の面積として求めます。1点の確率は0で、密度の値は1を超えることもあります。標準正規分布表は、この面積を z ごとに計算して並べた表です。

この記事でわかること

  • 確率質量関数・確率密度関数・累積分布関数の違いと、面積=確率を数値積分で確かめた結果
  • SciPy で計算した標準正規分布表(0.00〜3.09、下側・上側の2種類)と、読み方の手順
  • z 値への変換の例題(テスト・身長・偏差値)と、よくあるエラーの原文

2026年10月29日更新|Python 3.13・NumPy 2.5・SciPy 1.18で計算して確認

確率密度関数、累積分布関数、標準正規分布表は、同じ1本の曲線を別の向きから見たものです。関係を先に図にします。

flowchart TD
    A[確率密度関数 pdf<br>曲線の高さ] -->|左から面積を足す| B[累積分布関数 cdf<br>P X≦x]
    B -->|傾きをとる| A
    B -->|逆に引く| C[パーセント点 ppf<br>確率から x]
    B -->|z ごとに並べる| D[標準正規分布表]

よく調べられることの答えを先にまとめます。

知りたいこと 答え 詳しい節
確率密度関数とは 連続な値の出やすさの密度。区間の面積が確率 確率密度関数とは
確率質量関数との違い 質量関数は値そのものが確率(離散)。密度関数は面積が確率(連続) 3つの関数の違い
密度が1を超えてよいか 超えてよい。N(0, 0.1) の中心は 3.9894 だった 確率密度関数の性質
累積分布関数との関係 cdf は pdf を左から積分したもの。pdf は cdf の傾き 累積分布関数との関係
標準正規分布表の見方 z を「小数第1位まで」と「小数第2位」に分け、行と列の交点を読む 標準正規分布表の見方
z 値の求め方 z = (x − 平均) ÷ 標準偏差 z 値への変換と例題
1.96 の意味 上側確率 0.0250。両側で95%になる境目 標準正規分布表の見方
表を使わずに求めたい Python は norm.cdf、Excel は NORM.S.DIST Python・Excelで求める

確認環境:Ubuntu 24.04.5 LTS の上で、作業用のフォルダーに Python 3.13.18 の仮想環境(venv)を作り、NumPy 2.5.4 と SciPy 1.18.1 を pip で入れて計算しました。記事に載せた数値と標準正規分布表(0.00〜3.09 の310個)は、すべて記事中のコードを実行した出力で、表の値は scipy.integrate.quad による数値積分と、Python 標準ライブラリの statistics.NormalDist でも計算し、4桁ですべて一致することを確かめています。乱数は numpy.random.default_rng(0) で種を固定しています。Excel の関数(NORM.S.DIST・NORM.S.INV・NORM.DIST)は Excel を動かしておらず、Microsoft サポートの関数の説明で書式と例を確かめ、例の値を SciPy で計算して一致を確かめました。SciPy の関数の仕様は SciPy の公式ドキュメント(1.18.0)で確かめています。図は mermaid-cli 11.16.0 で描画を確かめました(確認日 2026年10月29日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「確率密度関数とは|標準正規分布表の見方と全310値をPythonで検算」

確率密度関数とは(意味を一言で)

この節では、確率密度関数が何を表す関数なのかが、身長の例で分かります。

確率密度関数(probability density function、略して pdf)は、身長や時間のように連続した値をとるもの(連続型の確率変数)について、「どのあたりの値が出やすいか」を密度で表す関数です。確率そのものではなく、ある範囲の確率は、その範囲でグラフの下にできる面積として求めます。

たとえば身長は 170cm、170.1cm、170.01cm…と、いくらでも細かく分けられます。「ちょうど 170.000…cm」の人の割合はいくら細かく測っても0に近づくため、連続な値では「1点の確率」を考えても意味がありません。そこで「169.5cm 以上 170.5cm 未満」のように範囲で確率を考え、その範囲の面積が確率になるように描いた曲線が確率密度関数です。

1高さは「密度」

曲線の高さは確率ではない。人口密度が「1平方キロメートルあたりの人数」であるのと同じく、「幅1あたりの確率」を表す。

2確率は「面積」

a から b までの確率は、a から b までの曲線の下の面積。式では P(a ≦ X ≦ b) = ∫[a→b] f(x) dx。

3全体の面積は1

どこかの値は必ず出るため、曲線の下の面積をすべて足すと1(100%)になる。

式の ∫[a→b] f(x) dx は「f(x) のグラフの下の、a から b までの面積」を表す記号(積分)です。積分の計算ができなくても、「面積を求めている」と読めれば、この記事の内容は追えます。後の節で、面積をプログラムで細かい台形に分けて足し、本当に確率と一致するかを確かめます。

SciPy では、分布ごとに pdf・cdf・ppf などの関数がそろっています。標準正規分布(平均0・標準偏差1の正規分布)で、それぞれを計算した結果です。

from scipy.stats import norm

for x in [0, 1, 1.96, 3]:
    print(f"x={x}: pdf={norm.pdf(x):.6f}  cdf={norm.cdf(x):.6f}  sf={norm.sf(x):.6f}")
for p in [0.5, 0.9, 0.95, 0.975, 0.99]:
    print(f"ppf({p}) = {norm.ppf(p):.6f}")
x=0: pdf=0.398942  cdf=0.500000  sf=0.500000
x=1: pdf=0.241971  cdf=0.841345  sf=0.158655
x=1.96: pdf=0.058441  cdf=0.975002  sf=0.024998
x=3: pdf=0.004432  cdf=0.998650  sf=0.001350
ppf(0.5) = 0.000000
ppf(0.9) = 1.281552
ppf(0.95) = 1.644854
ppf(0.975) = 1.959964
ppf(0.99) = 2.326348

pdf(0) = 0.398942 は、0 の付近の「密度」です。0 が出る確率が約40%という意味ではありません。cdf(1.96) = 0.975002 は「1.96 以下になる確率が約97.5%」、sf(survival function)は「その値以上になる確率(上側確率)」で、1 − cdf と同じ値です。ppf は cdf の逆で、確率から境目の値を求めます。

確率質量関数・確率密度関数・累積分布関数の違い

この節では、名前の似た3つの関数の違いと、どれを使えばよいかが一覧で分かります。

値そのものが確率になるのが確率質量関数(離散型)、面積が確率になるのが確率密度関数(連続型)、「その値以下になる確率」を返すのが累積分布関数(離散型・連続型の両方)です。

確率質量関数(pmf) 確率密度関数(pdf) 累積分布関数(cdf)
対象 離散型(サイコロ・回数) 連続型(身長・時間) 両方
返す値 その値になる確率 その値の付近の密度 その値以下になる確率
値の範囲 0〜1 0以上(1を超えてよい) 0〜1(右へ行くほど増える)
全体の合計 全部の値を足すと1 全体の面積が1 右端で1に近づく
区間の確率 当てはまる値の確率を足す 区間の面積(積分) F(b) − F(a)
SciPy の関数 pmf pdf cdf

サイコロ(1〜6が同じ確率で出る離散一様分布)と、10回コインを投げて表が出る回数(二項分布)で、確率質量関数と累積分布関数を計算しました。

from scipy import stats

die = stats.randint(1, 7)                       # 1〜6 のサイコロ
print("サイコロ: pmf(3) =", die.pmf(3), " cdf(3) =", die.cdf(3), " pmf(3.5) =", die.pmf(3.5))
b = stats.binom(10, 0.5)                        # 10回投げて表の回数
print("二項分布: pmf(3) =", b.pmf(3), " cdf(3) =", b.cdf(3), " cdf(2) =", b.cdf(2))
print("pmf(0)〜pmf(10) の合計 =", sum(b.pmf(k) for k in range(11)))
サイコロ: pmf(3) = 0.16666666666666666  cdf(3) = 0.5  pmf(3.5) = 0.0
二項分布: pmf(3) = 0.1171875  cdf(3) = 0.171875  cdf(2) = 0.0546875
pmf(0)〜pmf(10) の合計 = 0.9999999999999999

離散型では「3が出る確率」は 1/6 です。pmf(3.5) = 0.0 のように、出ない値の確率は0です。離散型では P(X ≦ 3)(0.171875)と P(X < 3)(0.0546875)が違うため、「以下」と「未満」を区別します。連続型では1点の確率が0なので、「以下」と「未満」は同じ値になります。合計が 0.9999999999999999 になっているのは、コンピューターの小数の計算で出る誤差で、数学的には1です。

離散型と連続型の見分け方

離散型数えられる値(0回・1回・2回…)。値ごとの確率を「棒」で表す。確率質量関数を使う
↔
連続型測る値(170.3cm・2.71秒)。曲線の下の面積で表す。確率密度関数を使う

見分ける問い:「その値と次の値のあいだに、別の値があり得るか」

教科書や記事によっては、離散型の確率質量関数を「確率関数」、両方をまとめて「確率分布」と呼ぶこともあります。確率分布の種類(二項分布・ポアソン分布・t分布など)の一覧と選び方は、関連記事「確率分布とは|種類一覧・平均と分散・選び方をPythonで実演」で扱っています。この記事は、確率密度関数と標準正規分布表に絞って詳しく見ていきます。

確率密度関数の性質(密度は1を超えることがある)

この節では、確率密度関数が満たす条件と、「密度が1を超えるのはおかしいのでは」という疑問への答えが、計算結果で分かります。

確率密度関数の条件は「どこでも0以上」と「全体の面積が1」の2つだけで、高さに上限はありません。幅の狭い分布ほど、面積を1に保つために山が高くなります。

  • 1どこでも0以上f(x) ≧ 0。負の密度は無い
  • 2全体の面積が1∫[−∞→∞] f(x) dx = 1
  • 31点の確率は0幅0の面積は0。P(X = a) = 0
  • 4高さに上限は無い1を超えても、面積が1なら正しい密度

平均0の正規分布で、標準偏差(ばらつきの大きさ)を 1 から 0.01 まで小さくし、中心の高さと全体の面積を計算しました。

import numpy as np
from scipy import integrate
from scipy.stats import norm, uniform

for s in [1, 0.5, 0.25, 0.1, 0.01]:
    d = norm(loc=0, scale=s)                      # 平均0・標準偏差 s
    area, _ = integrate.quad(d.pdf, -np.inf, np.inf)
    print(f"N(0, {s}): pdf(0) = {d.pdf(0):.4f}  全体の面積 = {area:.10f}")
u = uniform(loc=0, scale=0.25)                    # 0〜0.25 の一様分布
print("U(0, 0.25): pdf(0.1) =", u.pdf(0.1), " 全体の面積 =", integrate.quad(u.pdf, 0, 0.25)[0])
N(0, 1): pdf(0) = 0.3989  全体の面積 = 1.0000000000
N(0, 0.5): pdf(0) = 0.7979  全体の面積 = 1.0000000000
N(0, 0.25): pdf(0) = 1.5958  全体の面積 = 1.0000000000
N(0, 0.1): pdf(0) = 3.9894  全体の面積 = 1.0000000000
N(0, 0.01): pdf(0) = 39.8942  全体の面積 = 1.0000000000
U(0, 0.25): pdf(0.1) = 4.0  全体の面積 = 1.0

標準偏差 0.1 のとき中心の密度は 3.9894、0.01 のときは 39.8942 でしたが、全体の面積はどれも 1.0000000000 でした。0〜0.25 の一様分布(どの値も同じ出やすさ)も、高さは 4.0、面積は1です。幅0.25 × 高さ4 = 1 という長方形の面積を思い浮かべると分かりやすいでしょう。

分布 中心の密度 全体の面積
正規分布 標準偏差10.39891
正規分布 標準偏差0.50.79791
正規分布 標準偏差0.251.59581
正規分布 標準偏差0.13.98941
正規分布 標準偏差0.0139.89421
一様分布 0〜0.254.01

標準偏差を半分にすると、中心の密度はちょうど2倍になっています(0.3989 → 0.7979)。正規分布の中心の高さは 1 ÷ (標準偏差 × √(2π)) で、標準偏差に反比例するためです。

区間の確率=面積を数値積分で確かめる

この節では、「確率は曲線の下の面積」が本当に成り立つかを、数値積分と、自分で書いた台形公式で確かめた結果が分かります。

pdf を a から b まで数値積分した値と、cdf(b) − cdf(a) は、10桁まで一致しました。手で書いた台形公式でも、台形を細かくするほど同じ値に近づきます。

手順は次のとおりです。

1

区間を決める

-1 から 1 のように、確率を知りたい範囲を決める。

例:平均±1標準偏差

2

区間を n 本の細い台形に分ける

区間を n 等分し、各点で pdf の高さを計算する。隣り合う2点の高さで台形を作る。

n = 4, 10, 100, 1000

3

台形の面積を足す

台形1本の面積は「(左の高さ+右の高さ) ÷ 2 × 幅」。全部足したものが近似の面積になる。

コードの t

4

cdf の差と比べる

cdf(1) − cdf(−1) と比べ、誤差がどう縮むかを見る。

誤差 = 近似 − 正確な値

import numpy as np
from scipy import integrate
from scipy.stats import norm

for a, b in [(-1, 1), (-2, 2), (-3, 3), (0, 1.96), (1, 2)]:
    q, err = integrate.quad(norm.pdf, a, b)       # pdf を a〜b で数値積分
    print(f"[{a}, {b}]  積分 = {q:.10f}  cdf(b)-cdf(a) = {norm.cdf(b) - norm.cdf(a):.10f}")

# 台形公式を自分で書く(-1〜1 を n 本の台形に分ける)
exact = norm.cdf(1) - norm.cdf(-1)
for n in [4, 10, 100, 1000]:
    xs = np.linspace(-1, 1, n + 1)
    ys = norm.pdf(xs)
    h = 2 / n
    t = h * (ys.sum() - (ys[0] + ys[-1]) / 2)
    print(f"台形 n={n:4d}: {t:.10f}  誤差 = {t - exact:.2e}")

# 1点の確率と、幅を狭めたときの確率
print("P(X = 1) =", norm.cdf(1) - norm.cdf(1))
for w in [0.1, 0.01, 0.001]:
    p = norm.cdf(1 + w / 2) - norm.cdf(1 - w / 2)
    print(f"幅 {w}: 確率 = {p:.10f}  確率÷幅 = {p / w:.6f}")
[-1, 1]  積分 = 0.6826894921  cdf(b)-cdf(a) = 0.6826894921
[-2, 2]  積分 = 0.9544997361  cdf(b)-cdf(a) = 0.9544997361
[-3, 3]  積分 = 0.9973002039  cdf(b)-cdf(a) = 0.9973002039
[0, 1.96]  積分 = 0.4750021049  cdf(b)-cdf(a) = 0.4750021049
[1, 2]  積分 = 0.1359051220  cdf(b)-cdf(a) = 0.1359051220
台形 n=   4: 0.6725218292  誤差 = -1.02e-02
台形 n=  10: 0.6810741970  誤差 = -1.62e-03
台形 n= 100: 0.6826733605  誤差 = -1.61e-05
台形 n=1000: 0.6826893308  誤差 = -1.61e-07
P(X = 1) = 0.0
幅 0.1: 確率 = 0.0241970699  確率÷幅 = 0.241971
幅 0.01: 確率 = 0.0024197072  確率÷幅 = 0.241971
幅 0.001: 確率 = 0.0002419707  確率÷幅 = 0.241971
  • scipy.integrate.quad(数値積分の関数)で求めた面積と cdf(b) − cdf(a) は、どの区間でも10桁まで一致しました。
  • 自作の台形公式は、n を10倍にすると誤差がおよそ100分の1になりました(-1.62e-03 → -1.61e-05 → -1.61e-07)。台形公式の誤差は幅の2乗に比例するためです。
  • 1点の確率 P(X = 1) は 0.0 でした。幅を 0.1 → 0.01 → 0.001 と狭めると、確率も 0.0242 → 0.0024 → 0.00024 と0に近づきます。
  • 一方、「確率 ÷ 幅」はどの幅でも 0.241971 で、これは pdf(1) の値と同じです。密度が「幅1あたりの確率」だということが、数字で確かめられます。

[-1, 1] の 0.6827、[-2, 2] の 0.9545、[-3, 3] の 0.9973 は、正規分布の「68-95-99.7 則(平均±1・2・3標準偏差の内側に入る割合)」の値です。

累積分布関数・パーセント点(ppf)との関係

この節では、pdf と cdf がどう行き来できるのか、ppf が何をしているのかが、計算結果で分かります。

cdf は pdf を左端から x まで積分したもの(F(x) = ∫[−∞→x] f(t) dt)で、逆に pdf は cdf の傾き(微分 f(x) = F′(x))です。ppf(percent point function、パーセント点)は cdf の逆関数で、「下から何%の位置か」から x を求めます。

cdf の傾きを、x の少し右と少し左の差から求め((F(x+h) − F(x−h)) ÷ 2h)、pdf と比べました。

from scipy.stats import norm

h = 1e-5
for x in [-1, 0, 0.5, 2]:
    slope = (norm.cdf(x + h) - norm.cdf(x - h)) / (2 * h)   # cdf の傾き
    print(f"x={x:4}: cdf の傾き = {slope:.8f}  pdf = {norm.pdf(x):.8f}")
print("cdf(ppf(0.975)) =", norm.cdf(norm.ppf(0.975)))
x=  -1: cdf の傾き = 0.24197072  pdf = 0.24197072
x=   0: cdf の傾き = 0.39894228  pdf = 0.39894228
x= 0.5: cdf の傾き = 0.35206533  pdf = 0.35206533
x=   2: cdf の傾き = 0.05399097  pdf = 0.05399097
cdf(ppf(0.975)) = 0.975

傾きと pdf は8桁まで一致し、cdf(ppf(0.975)) は元の 0.975 に戻りました。

x から確率を求める

cdf(x):x 以下の確率(下側)

sf(x):x 以上の確率(上側)

標準正規分布表を「行と列 → 中の数字」の向きに読むのと同じ

確率から x を求める

ppf(p):下から p の位置の x

isf(p):上から p の位置の x

標準正規分布表を「中の数字 → 行と列」の向きに読むのと同じ(逆引き)

よく使う値です。下の表の ppf の値は、前の節の a_basic.py の出力です。

下側の確率 p ppf(p) よく出る使い方
0.50.000000中央値(平均と同じ)
0.91.281552上位10%の境
0.951.644854上位5%の境・片側5%の検定
0.9751.959964両側5%の検定・95%信頼区間
0.992.326348上位1%の境

正規分布とは(式・平均と標準偏差・68-95-99.7)

この節では、正規分布の確率密度関数の式の読み方と、形を決める2つの数が分かります。

正規分布は、平均を中心に左右対称な釣り鐘の形をした連続型の分布で、平均 μ(ミュー)と標準偏差 σ(シグマ)の2つの数だけで形が決まります。平均 μ・標準偏差 σ の正規分布を N(μ, σ²) と書きます。かっこの2つ目は分散(標準偏差の2乗)です。

確率密度関数の式は次のとおりです。

f(x) = 1 / (σ × √(2π)) × exp( −(x − μ)² / (2σ²) )

標準正規分布(μ = 0, σ = 1)では
f(z) = 1 / √(2π) × exp( −z² / 2 )

式を部分ごとに読むと、次のようになります。

  • (x − μ)²:平均からの離れ具合の2乗。平均から離れるほど大きくなる。
  • exp(−…):e(約2.718)の「マイナス何乗」。中身が大きいほど0に近づく。平均から離れるほど密度が小さくなるのはこの部分のため。
  • 1 / (σ × √(2π)):全体の面積をちょうど1にするための数。σ が小さいほど大きくなる(前の節の「密度が1を超える」理由)。

この式をそのまま Python で書いた値と、SciPy の norm.pdf は、f(0) = 0.3989422804014327、f(1) = 0.24197072451914337 で一致しました。正規分布の pdf を平均・分散の定義どおりに積分すると、平均は 0.0、分散は 1.000000000000001 になりました(最後の桁は計算の誤差)。

  • 平均・中央値・最頻値(いちばん多い値)が一致し、平均を中心に左右対称です。
  • 平均±1σ に約68.27%、±2σ に約95.45%、±3σ に約99.73% が入ります(前の節の数値積分の結果)。
  • 身長、測定の誤差、多くの人の試験の点数などが、おおよそ正規分布に近い形になります。一方、待ち時間・所得・ファイルの大きさのように、右に長く裾を引く分布は正規分布になりません。
  • 標本の平均は、元の分布が正規分布でなくても、標本の数を増やすと正規分布に近づきます(中心極限定理)。検定や信頼区間で正規分布がよく出てくる理由です。

一様分布・指数分布・正規分布の確率密度関数を比べる

この節では、よく出る3つの連続型の分布の確率密度関数を、同じ方法で計算して比べた結果が分かります。

3つとも「全体の面積が1」になる点は同じで、形・とれる値の範囲・平均と分散の求め方が違います。pdf を積分して面積・平均・分散を求め、SciPy の値と比べました。

import numpy as np
from scipy import integrate
from scipy.stats import uniform, expon, norm

dists = {"一様 U(0,10)": uniform(loc=0, scale=10),
         "指数 平均2": expon(scale=2),
         "正規 N(5,2)": norm(loc=5, scale=2)}
for name, d in dists.items():
    lo, hi = d.support()
    total = integrate.quad(d.pdf, lo, hi)[0]
    mean = integrate.quad(lambda t: t * d.pdf(t), lo, hi)[0]
    var = integrate.quad(lambda t: (t - mean) ** 2 * d.pdf(t), lo, hi)[0]
    print(f"{name}: 面積={total:.6f} 平均={mean:.4f} 分散={var:.4f} "
          f"pdf(1)={d.pdf(1):.4f} cdf(3)={d.cdf(3):.4f} 中央値={d.median():.4f}")

rng = np.random.default_rng(0)
rng.standard_normal(100_000)                     # f_hist.py と同じ順番で乱数を進める
u = rng.uniform(0, 10, 100_000)
e = rng.exponential(2, 100_000)
for name, s, d in [("一様", u, dists["一様 U(0,10)"]), ("指数", e, dists["指数 平均2"])]:
    c, ed = np.histogram(s, bins=[0, 2, 4, 6, 8, 10])
    theory = [round((d.cdf(ed[i + 1]) - d.cdf(ed[i])) * 1e5) for i in range(5)]
    print(name, "個数", c.tolist(), "理論", theory)
一様 U(0,10): 面積=1.000000 平均=5.0000 分散=8.3333 pdf(1)=0.1000 cdf(3)=0.3000 中央値=5.0000
指数 平均2: 面積=1.000000 平均=2.0000 分散=4.0000 pdf(1)=0.3033 cdf(3)=0.7769 中央値=1.3863
正規 N(5,2): 面積=1.000000 平均=5.0000 分散=4.0000 pdf(1)=0.0270 cdf(3)=0.1587 中央値=5.0000
一様 個数 [19879, 20244, 20039, 20041, 19797] 理論 [20000, 20000, 20000, 20000, 20000]
指数 個数 [63350, 23032, 8511, 3184, 1213] 理論 [63212, 23254, 8555, 3147, 1158]
分布 確率密度関数 とれる値 平均・分散(計算結果)
一様分布 U(0,10) 0〜10 で 1/10 の一定値 0〜10 平均 5・分散 8.3333
指数分布(平均2) (1/2) × exp(−x/2)。0 で最大、右へ減る 0以上 平均 2・分散 4・中央値 1.3863
正規分布 N(5, 2²) 5 を中心に左右対称の釣り鐘 すべての実数 平均 5・分散 4・中央値 5
  • 一様分布の分散は (幅)² ÷ 12 で、100 ÷ 12 = 8.3333 と一致しました。
  • 指数分布は、平均(2)より中央値(1.3863)が小さくなりました。右に長い裾がある分布では、平均が中央値より大きくなります。次にお客さんが来るまでの時間、機械が壊れるまでの時間などに使われます。
  • 指数分布の平均と分散が「平均2・分散4」と同じ数の組になるのは偶然ではなく、指数分布では常に「分散=平均の2乗」です。

乱数を10万個ずつ作って区間ごとに数えた結果(コードの最後の2行)も、理論の個数とほぼ一致しました。一様分布はどの区間もおよそ2万個、指数分布は 0〜2 に約63%が集まります。

乱数10万個のヒストグラムで確率密度を確かめる

この節では、実際のデータ(乱数)のヒストグラムから確率密度関数がどう見えるかが、グラフではなく数値の表で分かります。

ヒストグラムの「区間の割合 ÷ 区間の幅」は、確率密度の推定値になります。標準正規分布の乱数を10万個作り、0.5 刻みで数えました。

import numpy as np
from scipy.stats import norm

rng = np.random.default_rng(0)                   # 乱数の種を固定
x = rng.standard_normal(100_000)                 # 標準正規分布の乱数 10万個
print(f"平均 {x.mean():.4f}  標準偏差 {x.std(ddof=1):.4f}")
edges = np.arange(-3, 3.01, 0.5)
count, _ = np.histogram(x, bins=edges)
for i, c in enumerate(count):
    a, b = edges[i], edges[i + 1]
    print(f"[{a:+.1f},{b:+.1f}) 個数={c:6d} 割合={c/1e5:.4f} 理論={norm.cdf(b)-norm.cdf(a):.4f} "
          f"割合÷幅={c/1e5/0.5:.4f} 中央のpdf={norm.pdf((a+b)/2):.4f}")
for k in [1, 2, 3]:
    print(f"±{k}σの内側: {np.mean(np.abs(x) < k):.4f}  理論 {norm.cdf(k) - norm.cdf(-k):.4f}")
平均 -0.0009  標準偏差 1.0001
[-3.0,-2.5) 個数=   503 割合=0.0050 理論=0.0049 割合÷幅=0.0101 中央のpdf=0.0091
[-2.5,-2.0) 個数=  1630 割合=0.0163 理論=0.0165 割合÷幅=0.0326 中央のpdf=0.0317
[-2.0,-1.5) 個数=  4367 割合=0.0437 理論=0.0441 割合÷幅=0.0873 中央のpdf=0.0863
[-1.5,-1.0) 個数=  9200 割合=0.0920 理論=0.0918 割合÷幅=0.1840 中央のpdf=0.1826
[-1.0,-0.5) 個数= 14971 割合=0.1497 理論=0.1499 割合÷幅=0.2994 中央のpdf=0.3011
[-0.5,+0.0) 個数= 19348 割合=0.1935 理論=0.1915 割合÷幅=0.3870 中央のpdf=0.3867
[+0.0,+0.5) 個数= 18815 割合=0.1882 理論=0.1915 割合÷幅=0.3763 中央のpdf=0.3867
[+0.5,+1.0) 個数= 15257 割合=0.1526 理論=0.1499 割合÷幅=0.3051 中央のpdf=0.3011
[+1.0,+1.5) 個数=  9155 割合=0.0916 理論=0.0918 割合÷幅=0.1831 中央のpdf=0.1826
[+1.5,+2.0) 個数=  4347 割合=0.0435 理論=0.0441 割合÷幅=0.0869 中央のpdf=0.0863
[+2.0,+2.5) 個数=  1623 割合=0.0162 理論=0.0165 割合÷幅=0.0325 中央のpdf=0.0317
[+2.5,+3.0) 個数=   492 割合=0.0049 理論=0.0049 割合÷幅=0.0098 中央のpdf=0.0091
±1σの内側: 0.6839  理論 0.6827
±2σの内側: 0.9546  理論 0.9545
±3σの内側: 0.9971  理論 0.9973
区間 個数 割合(理論) 割合÷幅 中央の pdf
-3.0〜-2.55030.0050(0.0049)0.01010.0091
-2.5〜-2.01,6300.0163(0.0165)0.03260.0317
-2.0〜-1.54,3670.0437(0.0441)0.08730.0863
-1.5〜-1.09,2000.0920(0.0918)0.18400.1826
-1.0〜-0.514,9710.1497(0.1499)0.29940.3011
-0.5〜0.019,3480.1935(0.1915)0.38700.3867
0.0〜0.518,8150.1882(0.1915)0.37630.3867
0.5〜1.015,2570.1526(0.1499)0.30510.3011
1.0〜1.59,1550.0916(0.0918)0.18310.1826
1.5〜2.04,3470.0435(0.0441)0.08690.0863
2.0〜2.51,6230.0162(0.0165)0.03250.0317
2.5〜3.04920.0049(0.0049)0.00980.0091

1割合は理論とほぼ一致

区間の割合は、cdf の差から求めた理論値と、どの区間も小数第2位まで近い値になった。

2割合÷幅が pdf に近い

ヒストグラムの縦軸を「割合÷幅」にすると、pdf の曲線と重ねられる。np.histogram(..., density=True) がこの値を返す。

3裾ではずれが出る

-3.0〜-2.5 の「割合÷幅」0.0101 は中央の pdf 0.0091 より大きい。曲線が曲がっている所では、区間の中央の高さと区間の平均の高さが違うため。

平均±1σ・±2σ・±3σ の内側に入った割合は、0.6839・0.9546・0.9971 で、理論の 0.6827・0.9545・0.9973 に近い値でした。乱数なので、種を変えると小数第3位あたりが変わります。乱数の作り方の基本は、関連記事「Python randomの使い方一覧|randint・choice・shuffle」で扱っています。

標準正規分布表(0.00〜3.09)

この節では、SciPy で計算した標準正規分布表そのもの(下側累積確率と上側確率の2種類)と、表の種類の見分け方が分かります。

標準正規分布表は、標準正規分布の曲線の下の面積を、z = 0.00 から 3.09 まで 0.01 刻みで計算して並べた表です。行が z の小数第1位まで、列が z の小数第2位です。表を作るコードは次の12行です。

from scipy.stats import norm

def show(f, title):
    print(title)
    print("z    " + "".join(f"   .0{i}  " for i in range(10)))
    for r in range(31):                  # 0.0, 0.1, ..., 3.0
        z0 = r / 10
        print(f"{z0:.1f} " + "".join(f" {f(z0 + c / 100):.4f} " for c in range(10)))

show(norm.cdf, "下側累積確率 P(Z ≦ z)")
show(norm.sf, "上側確率 P(Z ≧ z)")

下側累積確率の表 P(Z ≦ z)

z 以下になる確率(左端から z までの面積)です。norm.cdf や Excel の NORM.S.DIST(z, TRUE) と同じ値です。

下側累積確率 P(Z ≦ z)
z       .00     .01     .02     .03     .04     .05     .06     .07     .08     .09  
0.0  0.5000  0.5040  0.5080  0.5120  0.5160  0.5199  0.5239  0.5279  0.5319  0.5359 
0.1  0.5398  0.5438  0.5478  0.5517  0.5557  0.5596  0.5636  0.5675  0.5714  0.5753 
0.2  0.5793  0.5832  0.5871  0.5910  0.5948  0.5987  0.6026  0.6064  0.6103  0.6141 
0.3  0.6179  0.6217  0.6255  0.6293  0.6331  0.6368  0.6406  0.6443  0.6480  0.6517 
0.4  0.6554  0.6591  0.6628  0.6664  0.6700  0.6736  0.6772  0.6808  0.6844  0.6879 
0.5  0.6915  0.6950  0.6985  0.7019  0.7054  0.7088  0.7123  0.7157  0.7190  0.7224 
0.6  0.7257  0.7291  0.7324  0.7357  0.7389  0.7422  0.7454  0.7486  0.7517  0.7549 
0.7  0.7580  0.7611  0.7642  0.7673  0.7704  0.7734  0.7764  0.7794  0.7823  0.7852 
0.8  0.7881  0.7910  0.7939  0.7967  0.7995  0.8023  0.8051  0.8078  0.8106  0.8133 
0.9  0.8159  0.8186  0.8212  0.8238  0.8264  0.8289  0.8315  0.8340  0.8365  0.8389 
1.0  0.8413  0.8438  0.8461  0.8485  0.8508  0.8531  0.8554  0.8577  0.8599  0.8621 
1.1  0.8643  0.8665  0.8686  0.8708  0.8729  0.8749  0.8770  0.8790  0.8810  0.8830 
1.2  0.8849  0.8869  0.8888  0.8907  0.8925  0.8944  0.8962  0.8980  0.8997  0.9015 
1.3  0.9032  0.9049  0.9066  0.9082  0.9099  0.9115  0.9131  0.9147  0.9162  0.9177 
1.4  0.9192  0.9207  0.9222  0.9236  0.9251  0.9265  0.9279  0.9292  0.9306  0.9319 
1.5  0.9332  0.9345  0.9357  0.9370  0.9382  0.9394  0.9406  0.9418  0.9429  0.9441 
1.6  0.9452  0.9463  0.9474  0.9484  0.9495  0.9505  0.9515  0.9525  0.9535  0.9545 
1.7  0.9554  0.9564  0.9573  0.9582  0.9591  0.9599  0.9608  0.9616  0.9625  0.9633 
1.8  0.9641  0.9649  0.9656  0.9664  0.9671  0.9678  0.9686  0.9693  0.9699  0.9706 
1.9  0.9713  0.9719  0.9726  0.9732  0.9738  0.9744  0.9750  0.9756  0.9761  0.9767 
2.0  0.9772  0.9778  0.9783  0.9788  0.9793  0.9798  0.9803  0.9808  0.9812  0.9817 
2.1  0.9821  0.9826  0.9830  0.9834  0.9838  0.9842  0.9846  0.9850  0.9854  0.9857 
2.2  0.9861  0.9864  0.9868  0.9871  0.9875  0.9878  0.9881  0.9884  0.9887  0.9890 
2.3  0.9893  0.9896  0.9898  0.9901  0.9904  0.9906  0.9909  0.9911  0.9913  0.9916 
2.4  0.9918  0.9920  0.9922  0.9925  0.9927  0.9929  0.9931  0.9932  0.9934  0.9936 
2.5  0.9938  0.9940  0.9941  0.9943  0.9945  0.9946  0.9948  0.9949  0.9951  0.9952 
2.6  0.9953  0.9955  0.9956  0.9957  0.9959  0.9960  0.9961  0.9962  0.9963  0.9964 
2.7  0.9965  0.9966  0.9967  0.9968  0.9969  0.9970  0.9971  0.9972  0.9973  0.9974 
2.8  0.9974  0.9975  0.9976  0.9977  0.9977  0.9978  0.9979  0.9979  0.9980  0.9981 
2.9  0.9981  0.9982  0.9982  0.9983  0.9984  0.9984  0.9985  0.9985  0.9986  0.9986 
3.0  0.9987  0.9987  0.9987  0.9988  0.9988  0.9989  0.9989  0.9989  0.9990  0.9990 

上側確率の表 P(Z ≧ z)

z 以上になる確率(z から右端までの面積)です。norm.sf と同じ値で、統計の検定の教科書でよく使われる形です。

上側確率 P(Z ≧ z)
z       .00     .01     .02     .03     .04     .05     .06     .07     .08     .09  
0.0  0.5000  0.4960  0.4920  0.4880  0.4840  0.4801  0.4761  0.4721  0.4681  0.4641 
0.1  0.4602  0.4562  0.4522  0.4483  0.4443  0.4404  0.4364  0.4325  0.4286  0.4247 
0.2  0.4207  0.4168  0.4129  0.4090  0.4052  0.4013  0.3974  0.3936  0.3897  0.3859 
0.3  0.3821  0.3783  0.3745  0.3707  0.3669  0.3632  0.3594  0.3557  0.3520  0.3483 
0.4  0.3446  0.3409  0.3372  0.3336  0.3300  0.3264  0.3228  0.3192  0.3156  0.3121 
0.5  0.3085  0.3050  0.3015  0.2981  0.2946  0.2912  0.2877  0.2843  0.2810  0.2776 
0.6  0.2743  0.2709  0.2676  0.2643  0.2611  0.2578  0.2546  0.2514  0.2483  0.2451 
0.7  0.2420  0.2389  0.2358  0.2327  0.2296  0.2266  0.2236  0.2206  0.2177  0.2148 
0.8  0.2119  0.2090  0.2061  0.2033  0.2005  0.1977  0.1949  0.1922  0.1894  0.1867 
0.9  0.1841  0.1814  0.1788  0.1762  0.1736  0.1711  0.1685  0.1660  0.1635  0.1611 
1.0  0.1587  0.1562  0.1539  0.1515  0.1492  0.1469  0.1446  0.1423  0.1401  0.1379 
1.1  0.1357  0.1335  0.1314  0.1292  0.1271  0.1251  0.1230  0.1210  0.1190  0.1170 
1.2  0.1151  0.1131  0.1112  0.1093  0.1075  0.1056  0.1038  0.1020  0.1003  0.0985 
1.3  0.0968  0.0951  0.0934  0.0918  0.0901  0.0885  0.0869  0.0853  0.0838  0.0823 
1.4  0.0808  0.0793  0.0778  0.0764  0.0749  0.0735  0.0721  0.0708  0.0694  0.0681 
1.5  0.0668  0.0655  0.0643  0.0630  0.0618  0.0606  0.0594  0.0582  0.0571  0.0559 
1.6  0.0548  0.0537  0.0526  0.0516  0.0505  0.0495  0.0485  0.0475  0.0465  0.0455 
1.7  0.0446  0.0436  0.0427  0.0418  0.0409  0.0401  0.0392  0.0384  0.0375  0.0367 
1.8  0.0359  0.0351  0.0344  0.0336  0.0329  0.0322  0.0314  0.0307  0.0301  0.0294 
1.9  0.0287  0.0281  0.0274  0.0268  0.0262  0.0256  0.0250  0.0244  0.0239  0.0233 
2.0  0.0228  0.0222  0.0217  0.0212  0.0207  0.0202  0.0197  0.0192  0.0188  0.0183 
2.1  0.0179  0.0174  0.0170  0.0166  0.0162  0.0158  0.0154  0.0150  0.0146  0.0143 
2.2  0.0139  0.0136  0.0132  0.0129  0.0125  0.0122  0.0119  0.0116  0.0113  0.0110 
2.3  0.0107  0.0104  0.0102  0.0099  0.0096  0.0094  0.0091  0.0089  0.0087  0.0084 
2.4  0.0082  0.0080  0.0078  0.0075  0.0073  0.0071  0.0069  0.0068  0.0066  0.0064 
2.5  0.0062  0.0060  0.0059  0.0057  0.0055  0.0054  0.0052  0.0051  0.0049  0.0048 
2.6  0.0047  0.0045  0.0044  0.0043  0.0041  0.0040  0.0039  0.0038  0.0037  0.0036 
2.7  0.0035  0.0034  0.0033  0.0032  0.0031  0.0030  0.0029  0.0028  0.0027  0.0026 
2.8  0.0026  0.0025  0.0024  0.0023  0.0023  0.0022  0.0021  0.0021  0.0020  0.0019 
2.9  0.0019  0.0018  0.0018  0.0017  0.0016  0.0016  0.0015  0.0015  0.0014  0.0014 
3.0  0.0013  0.0013  0.0013  0.0012  0.0012  0.0011  0.0011  0.0011  0.0010  0.0010 

表の値を別の方法で確かめた結果

310個の値を、数値積分(0.5 + ∫[0→z] f(t) dt)と、Python 標準ライブラリの statistics.NormalDist でも計算し、比べました。

import numpy as np
from statistics import NormalDist
from scipy import integrate
from scipy.stats import norm

zs = np.round(np.arange(0, 3.1, 0.01), 2)          # 0.00〜3.09 の 310 個
nd = NormalDist()                                  # Python 標準ライブラリ
d_quad = max(abs(0.5 + integrate.quad(norm.pdf, 0, z)[0] - norm.cdf(z)) for z in zs)
d_std = max(abs(nd.cdf(z) - norm.cdf(z)) for z in zs)
mismatch = sum(f"{nd.cdf(z):.4f}" != f"{norm.cdf(z):.4f}" for z in zs)
print("セル数", len(zs), " 積分との最大差", d_quad, " NormalDist との最大差", d_std, " 4桁で違うセル", mismatch)
for z in [0.74, 1.25, 2.0, 3.0]:
    print(f"z={z}: P(Z≦z) = {norm.cdf(z):.10f}")
セル数 310  積分との最大差 2.220446049250313e-16  NormalDist との最大差 1.1102230246251565e-16  4桁で違うセル 0
z=0.74: P(Z≦z) = 0.7703500028
z=1.25: P(Z≦z) = 0.8943502263
z=2.0: P(Z≦z) = 0.9772498681
z=3.0: P(Z≦z) = 0.9986501020

3つの方法の差は最大でも 2.2 × 10⁻¹⁶(コンピューターの小数の精度の限界)で、4桁に丸めた値は310個すべて一致しました。z = 0.74 の値は 0.7703500028 で、小数第5位がちょうど5に近いため、4桁に丸めると 0.7704 になります。このように小数第5位が5の前後になるセルでは、計算や丸め方の違う表と最後の1桁が違うことがあります。

表の種類は3つある(見分け方)

本や試験によって、表に載っている面積が違います。同じ z = 1.00 でも、表の数字が違います。

表の種類 表している面積 z = 0.00 の値 z = 1.00 の値
下側累積確率左端から z まで P(Z ≦ z)0.50000.8413
上側確率z から右端まで P(Z ≧ z)0.50000.1587
0 から z まで中心から z まで P(0 ≦ Z ≦ z)0.00000.3413
  • z = 0.00 の値が 0.0000 なら「0 から z まで」の表(高校の数学Bの教科書でよく使われる形)。
  • z = 0.00 が 0.5000 で、下へ行くほど増えるなら下側累積確率、減るなら上側確率の表。
  • 3つは互いに変換できる:上側 = 1 − 下側、0からz = 下側 − 0.5。

標準正規分布表の見方(一歩ずつ)

この節では、標準正規分布表から確率を読む手順と、負の z・区間・逆引きの読み方が、例題で分かります。

z を「小数第1位まで」と「小数第2位」に分け、行と列の交わるところを読みます。ここでは上の「下側累積確率の表」を使います。

1

表の種類を確かめる

z = 0.00 の値と、下へ行くと増えるか減るかを見る。この節では下側累積確率の表を使う。

0.5000 で増える → 下側累積

2

z を2つに分ける

z = 1.96 なら「1.9」と「0.06」に分ける。

1.96 = 1.9 + 0.06

3

行と列を探す

左端の列で「1.9」の行を、上端の行で「.06」の列を探す。

行 1.9 × 列 .06

4

交わるところを読む

0.9750 と読める。「Z が 1.96 以下になる確率は 97.50%」。

P(Z ≦ 1.96) = 0.9750

5

聞かれている面積に直す

「1.96 以上」なら 1 − 0.9750 = 0.0250。面積の図を頭に描き、左側か右側か、区間かを決めて引き算する。

P(Z ≧ 1.96) = 0.0250

パターン別の読み方

聞かれていること 下側累積の表での求め方 例(表の値で計算)
P(Z ≦ a)表の値をそのまま読むP(Z ≦ 1.00) = 0.8413
P(Z ≧ a)1 − 表の値P(Z ≧ 1.50) = 1 − 0.9332 = 0.0668
P(Z ≦ −a)(負の z)左右対称なので 1 − P(Z ≦ a)P(Z ≦ −1.50) = 0.0668
P(a ≦ Z ≦ b)P(Z ≦ b) − P(Z ≦ a)P(0.50 ≦ Z ≦ 1.50) = 0.9332 − 0.6915 = 0.2417
P(−a ≦ Z ≦ a)2 × P(Z ≦ a) − 1P(−1.96 ≦ Z ≦ 1.96) = 0.9500
P(−a ≦ Z ≦ b)P(Z ≦ b) − (1 − P(Z ≦ a))P(−1 ≦ Z ≦ 2) = 0.9772 − 0.1587 = 0.8185

表に負の z が無いのは、標準正規分布が 0 を中心に左右対称で、P(Z ≦ −a) = P(Z ≧ a) が成り立つからです。手元でも norm.cdf(-1.96) と 1 - norm.cdf(1.96) はどちらも 0.0249978951482204… で、最後の桁の誤差を除いて一致しました。

最後の行の P(−1 ≦ Z ≦ 2) は、SciPy で直接計算すると 0.818595 で、4桁に丸めると 0.8186 です。表の値(4桁に丸めた値)どうしを引き算すると 0.8185 になり、最後の1桁がずれました。表を使った答えは、丸めの誤差で最後の1桁が違うことがあります。

逆引き:確率から z を求める

「上位5%に入る z はいくつか」のように、確率から z を求めるときは、表の中から確率を探して行と列を読みます。

  1. 1下側の確率に直す上位5% → 下から95% → 0.9500 を探す
  2. 2表の中で 0.9500 に近い値を探す1.64 の位置が 0.9495、1.65 の位置が 0.9505
  3. 3ちょうど間なら真ん中をとるz ≒ 1.645(SciPy の norm.ppf(0.95) は 1.644854)
  4. 4元の単位に戻すx = 平均 + z × 標準偏差

表の2つの値のあいだを直線で結んで読む方法(線形補間)もあります。z = 1.235 のとき、1.23 の 0.8907 と 1.24 の 0.8925 の真ん中は 0.8916 で、SciPy で計算した 0.891585 を4桁に丸めた値と同じでした。

3.09 より大きい z

この記事の表は 3.09 までです。それより大きい z の上側確率は、表の最後の 0.0010 よりさらに小さくなります。SciPy の norm.sf で計算した値です。

z=3.09: 上側確率 1.001e-03
z=3.5 : 上側確率 2.326e-04
z=4   : 上側確率 3.167e-05
z=5   : 上側確率 2.867e-07
z=6   : 上側確率 9.866e-10

z値への変換と例題(テスト・身長・偏差値)

この節では、平均や標準偏差が0・1でない正規分布を、z 値に直して標準正規分布表で読む手順が、例題で分かります。

z 値は z = (x − 平均) ÷ 標準偏差 で求めます。「平均から標準偏差いくつ分離れているか」を表す数で、この変換を標準化と呼びます。どんな平均・標準偏差の正規分布も、標準化すると標準正規分布になるため、1枚の表で済みます。

例題1:テストで75点以上の割合

平均60点・標準偏差10点で正規分布に従うテストで、75点以上の人の割合を求めます。

1

z 値に直す

z = (75 − 60) ÷ 10 = 1.5

平均から標準偏差1.5個分、上

2

表を読む

下側累積の表で行 1.5・列 .00 は 0.9332。

P(Z ≦ 1.50) = 0.9332

3

上側に直す

1 − 0.9332 = 0.0668。75点以上は約6.68%。

上側確率の表なら 0.0668 を直接読める

例題2〜5を Python で確かめる

from statistics import NormalDist
from scipy.stats import norm

# 例1:平均60点・標準偏差10点のテストで75点以上の割合
z = (75 - 60) / 10
print("z =", z, " 上側確率 =", round(norm.sf(z), 4), " 直接 =", round(norm.sf(75, loc=60, scale=10), 4))
# 例2:45点以上80点以下
print("45〜80点 =", round(norm.cdf(80, 60, 10) - norm.cdf(45, 60, 10), 4))
# 例3:上位10%に入る点数
print("上位10%の境 =", round(norm.ppf(0.9, 60, 10), 2), " z =", round(norm.ppf(0.9), 4))
# 例4:身長 平均170cm・標準偏差6cm
print("180cm以上 =", round(norm.sf(180, 170, 6), 4), " 165〜175cm =", round(norm.cdf(175, 170, 6) - norm.cdf(165, 170, 6), 4))
# 例5:偏差値(平均50・標準偏差10)
for h in [55, 60, 65, 70, 75]:
    print(f"偏差値{h}: 上位 {norm.sf((h - 50) / 10) * 100:.2f}%")
# 表の丸めの差
print("P(-1≦Z≦2) 正確 =", round(norm.cdf(2) - norm.cdf(-1), 6), " 4桁の表から =", round(0.9772 - (1 - 0.8413), 4))
# 標準ライブラリだけで
nd = NormalDist(mu=60, sigma=10)
print("NormalDist:", round(nd.cdf(75), 6), round(nd.inv_cdf(0.9), 4), round(NormalDist().pdf(0), 6))
z = 1.5  上側確率 = 0.0668  直接 = 0.0668
45〜80点 = 0.9104
上位10%の境 = 72.82  z = 1.2816
180cm以上 = 0.0478  165〜175cm = 0.5953
偏差値55: 上位 30.85%
偏差値60: 上位 15.87%
偏差値65: 上位 6.68%
偏差値70: 上位 2.28%
偏差値75: 上位 0.62%
P(-1≦Z≦2) 正確 = 0.818595  4桁の表から = 0.8185
NormalDist: 0.933193 72.8155 0.398942
例題 z 値 表での求め方 答え
テスト 45〜80点−1.5 と 2.00.9772 − (1 − 0.9332)0.9104
テスト 上位10%の点数1.28160.9000 に近い 1.28(0.8997)を逆引き約72.8点
身長 平均170・標準偏差6 で180cm以上1.67(1.666…)1 − 0.95250.0475(正確には 0.0478)
身長 165〜175cm−0.83 と 0.832 × 0.7967 − 10.5934(正確には 0.5953)
偏差値70の上位の割合2.01 − 0.97722.28%

身長の例では、z が 1.666… や 0.8333… のように割り切れないため、表で読むために小数第2位に丸めた分だけ、答えが SciPy の値とずれました。z を小数第2位に丸めると、確率で0.001〜0.002程度ずれることがあります。試験では表で、仕事のデータ分析ではプログラムで計算するのが確実です。

偏差値は「平均50・標準偏差10」に揃えた点数で、偏差値 = 50 + 10 × z です。得点が正規分布に従うと考えたとき、偏差値55は上位30.85%、60は上位15.87%、65は上位6.68%、70は上位2.28%、75は上位0.62%にあたります。実際の試験の点数は正規分布からずれることがあるため、目安として使います。

Python・Excelで標準正規分布表の値を求める

この節では、表を使わずに、Python(SciPy・標準ライブラリ)と Excel で同じ値を求める方法が、対応表で分かります。

Python では SciPy の scipy.stats.norm、SciPy を入れられない環境では標準ライブラリの statistics.NormalDist、Excel では NORM.S.DIST と NORM.S.INV を使います。

求めたいもの SciPy 標準ライブラリ Excel
密度 pdfnorm.pdf(z)NormalDist().pdf(z)NORM.S.DIST(z, FALSE)
下側累積 P(Z≦z)norm.cdf(z)NormalDist().cdf(z)NORM.S.DIST(z, TRUE)
上側 P(Z≧z)norm.sf(z)1 - NormalDist().cdf(z)1 - NORM.S.DIST(z, TRUE)
逆引き(確率→z)norm.ppf(p)NormalDist().inv_cdf(p)NORM.S.INV(p)
平均・標準偏差つきnorm.cdf(x, loc=μ, scale=σ)NormalDist(μ, σ).cdf(x)NORM.DIST(x, μ, σ, TRUE)
  • 標準ライブラリの NormalDist は、追加のインストール無しで使えます。手元では NormalDist(60, 10).cdf(75) が 0.933193、inv_cdf(0.9) が 72.8155 で、SciPy と同じ値でした。
  • Microsoft サポートの NORM.S.DIST の例は、=NORM.S.DIST(1.333333,TRUE) が 0.908788726、FALSE が 0.164010148 です。SciPy で計算すると norm.cdf(1.333333) = 0.9087887256、norm.pdf(1.333333) = 0.1640101476 で一致しました。
  • NORM.S.INV の例 =NORM.S.INV(0.908789) は 1.3333347 で、norm.ppf(0.908789) = 1.3333346730 と一致しました。Microsoft サポートによると、NORM.S.INV は確率が0以下か1以上のとき #NUM! エラーを返します。
  • NORM.DIST の例(x = 42・平均40・標準偏差1.5)は TRUE で 0.9087888、FALSE で 0.10934 で、norm.cdf(42, 40, 1.5) = 0.9087887803、norm.pdf(42, 40, 1.5) = 0.1093400498 と一致しました。

SciPy の公式ドキュメント(1.18.0)には、stats.Normal(mu=60, sigma=10) のような新しい書き方も載っています。手元の SciPy 1.18.1 では、Normal(mu=60, sigma=10).cdf(75) が 0.9331927987、.icdf(0.9) が 72.8155、.ccdf(75)(上側)が 0.0668072013 でした。逆関数の名前が ppf ではなく icdf になっている点が違います。配列の計算は、関連記事「NumPyの使い方 基本一覧|配列の作成・演算・形状変更」で扱っています。

よくあるエラーとつまずき(原文つき)と判断表

この節では、確率密度関数や正規分布を計算するときに出たエラーの原文と、エラーにならないのに結果が間違うつまずきが分かります。

SciPy は、範囲外の入力に対してエラーを出さずに nan を返すことが多く、気づきにくいつまずきになります。手元で実行した結果です。

import numpy as np
from scipy import integrate, stats
from scipy.stats import norm, expon

print("quad 細い分布:", integrate.quad(norm(0, 0.001).pdf, -100, 100))
print("quad 範囲を狭める:", integrate.quad(norm(0, 0.001).pdf, -0.01, 0.01))
print("norm(0, 4).var() =", norm(0, 4).var())
print("expon(2).mean() =", expon(2).mean(), " expon(scale=2).mean() =", expon(scale=2).mean())
print("norm.pdf(0, scale=-1) =", norm.pdf(0, scale=-1))
print("norm.ppf(1.2) =", norm.ppf(1.2), " ppf(0) =", norm.ppf(0), " ppf(1) =", norm.ppf(1))
print("1 - norm.cdf(9) =", 1 - norm.cdf(9), " norm.sf(9) =", norm.sf(9))
for code in ["stats.binom.pdf(3, 10, 0.5)", "norm.pmf(0)",
             "np.random.default_rng(0).normal(0, -1, 3)", "norm.cdf('1.0')"]:
    try:
        print(code, "->", eval(code))
    except Exception as ex:
        print(code, "->", f"{type(ex).__name__}: {ex}")
quad 細い分布: (0.0, 0.0)
quad 範囲を狭める: (1.0000000000000002, 8.671030676110766e-10)
norm(0, 4).var() = 16.0
expon(2).mean() = 3.0  expon(scale=2).mean() = 2.0
norm.pdf(0, scale=-1) = nan
norm.ppf(1.2) = nan  ppf(0) = -inf  ppf(1) = inf
1 - norm.cdf(9) = 0.0  norm.sf(9) = 1.1285884059538324e-19
stats.binom.pdf(3, 10, 0.5) -> AttributeError: 'binom_gen' object has no attribute 'pdf'
norm.pmf(0) -> AttributeError: 'norm_gen' object has no attribute 'pmf'
np.random.default_rng(0).normal(0, -1, 3) -> ValueError: scale < 0
norm.cdf('1.0') -> UFuncTypeError: ufunc 'subtract' did not contain a loop with signature matching types (dtype('<U3'), dtype('int64')) -> None

SciPy を入れていない Python で from scipy.stats import norm を実行すると、次のエラーになりました。

ModuleNotFoundError: No module named 'scipy'
出たもの(原文) 原因 直し方
AttributeError: 'binom_gen' object has no attribute 'pdf'離散型の分布に pdf を使った離散型は pmf、連続型は pdf
AttributeError: 'norm_gen' object has no attribute 'pmf'連続型の分布に pmf を使ったpdf を使う
ValueError: scale < 0NumPy の乱数で標準偏差に負の値を渡した標準偏差は0以上で渡す
UFuncTypeError: ufunc 'subtract' did not contain a loop …文字列 '1.0' を渡した(CSV の読み込み直後など)float() で数に直す
ModuleNotFoundError: No module named 'scipy'実行している Python に SciPy が無い同じ Python で python -m pip install scipy。または NormalDist を使う
nan(エラーにならない)scale=-1、ppf(1.2) など範囲外標準偏差は正、確率は0〜1で渡す

エラーが出ないのに結果が間違う例

やってはいけないnorm(0, 4) を「分散4」のつもりで使う。SciPy の2つ目は標準偏差で、var() は 16.0 になった
→
代わりにnorm(loc=0, scale=2) と名前つきで標準偏差を渡す。分散4なら標準偏差は2

N(μ, σ²) の2つ目は分散、SciPy・NumPy・Excel の引数は標準偏差

  • expon(2) は「平均2の指数分布」ではありません。最初の引数は位置(loc)で、平均は 3.0 になりました。平均2なら expon(scale=2) と書きます(平均 2.0)。
  • 幅の狭い分布を広い範囲で数値積分すると、0 になることがあります。標準偏差 0.001 の正規分布を -100〜100 で quad すると (0.0, 0.0) で、誤差の見積もりも 0 でした。山のある -0.01〜0.01 に範囲を絞ると 1.0000000000000002 になりました。積分の範囲は山を含む狭い範囲にするか、cdf の差を使います。
  • 上側の小さな確率を 1 - cdf で求めると 0 になります。1 - norm.cdf(9) は 0.0 でしたが、norm.sf(9) は 1.1285884059538324e-19 でした。上側は sf を使います。SciPy の公式ドキュメントも、sf は 1 - cdf と同じ定義だが、sf のほうが正確な場合がある、と説明しています。

どれを使うか(判断表)

やりたいこと 使うもの 理由
試験・手計算で正規分布の確率標準正規分布表z を小数第2位まで求め、表を読む
データ分析で確率を正確にSciPy の cdf・sf丸めの誤差が出ない。z を丸めなくてよい
SciPy を入れられない環境statistics.NormalDist標準ライブラリだけで同じ値
表計算ソフトの中でNORM.S.DIST・NORM.DISTTRUE で累積、FALSE で密度
確率から境目の値ppf・NORM.S.INV・表の逆引き上位◯%の点数、検定の棄却域
1点の「起こりやすさ」の比較pdf確率ではなく密度。尤度(もっともらしさ)の計算に使う
非常に小さい上側確率sf・logsf1 - cdf は 0 になる

検定で z や p 値を読む場面は、関連記事「p値とは|意味・有意水準・よくある誤解をPythonで実演」と関連記事「ABテストとは|やり方・サンプルサイズ・有意差の判定をPythonで実演」で扱っています。

よくある質問

Q. 確率密度関数とは何ですか? A. 連続な値をとるもの(身長・時間など)について、どのあたりの値が出やすいかを「密度」で表す関数です。ある範囲の確率は、その範囲の曲線の下の面積で求めます。全体の面積は1です。

Q. 確率密度関数の値は確率ですか? A. 確率ではありません。「幅1あたりの確率」です。手元の計算でも、x = 1 の付近の幅 0.001 の確率は 0.00024197 で、幅で割ると pdf(1) の 0.241971 になりました。

Q. 確率密度関数の値が1を超えてもよいのですか? A. 超えてよい値です。標準偏差 0.1 の正規分布では中心の密度が 3.9894 でしたが、全体の面積は1でした。条件は「0以上」と「全体の面積が1」だけです。

Q. 確率質量関数と確率密度関数の違いは? A. 確率質量関数は離散型(サイコロの目など)で、値そのものが確率です。確率密度関数は連続型で、面積が確率です。SciPy では離散型が pmf、連続型が pdf で、取り違えると AttributeError になります。

Q. 累積分布関数と確率密度関数の関係は? A. 累積分布関数は確率密度関数を左端から x まで積分したもの(x 以下の確率)で、確率密度関数は累積分布関数の傾き(微分)です。手元で cdf の傾きと pdf が8桁まで一致しました。

Q. 標準正規分布表の見方を簡単に教えてください。 A. z を「小数第1位まで」と「小数第2位」に分け、左端の行と上端の列が交わるところを読みます。z = 1.96 なら行 1.9・列 .06 で、下側累積の表なら 0.9750、上側確率の表なら 0.0250 です。

Q. 表に負の z がありません。 A. 標準正規分布は左右対称なので、P(Z ≦ −a) = P(Z ≧ a) = 1 − P(Z ≦ a) で求めます。P(Z ≦ −1.5) は 1 − 0.9332 = 0.0668 です。

Q. 本によって表の数字が違うのはなぜですか? A. 表している面積が違うためです(下側累積・上側・0 から z まで)。z = 0.00 の値が 0.0000 なら「0 から z まで」、0.5000 なら下側か上側です。また、小数第5位が5に近いセル(z = 0.74 の 0.77035000 など)は、丸め方で最後の1桁が違う表があります。

Q. z 値はどう求めますか? A. z = (x − 平均) ÷ 標準偏差 です。平均60点・標準偏差10点で75点なら z = 1.5 で、75点以上は約6.68%です。

Q. 1.96 や 1.645 はどこから来た数ですか? A. 1.96 は上側確率が 0.025(両側で5%)になる z で、norm.ppf(0.975) は 1.959964 でした。1.645 は上側確率が 0.05(片側5%)になる z で、norm.ppf(0.95) は 1.644854 でした。

Q. 表の 3.09 より大きい z の確率は? A. 表の外は SciPy の norm.sf で求めます。z = 4 の上側確率は 3.167 × 10⁻⁵、z = 5 は 2.867 × 10⁻⁷ でした。1 - norm.cdf(z) は z が大きいと 0 になるので使いません。

Q. Excel で標準正規分布表を作れますか? A. 下側累積なら NORM.S.DIST(z, TRUE)、上側なら 1 - NORM.S.DIST(z, TRUE) を、行と列の z を足したセルに入れて並べると作れます。Microsoft サポートの例の値は SciPy の計算と一致しました。

まとめ

  • 確率密度関数(pdf)は連続な値の「出やすさの密度」で、確率は区間の面積。1点の確率は0で、密度は1を超えてよい(N(0, 0.1) の中心は 3.9894、面積は1)。
  • 確率質量関数は離散型で値そのものが確率、累積分布関数は「x 以下の確率」。cdf は pdf の積分、pdf は cdf の傾きで、数値で8〜10桁まで一致した。
  • 標準正規分布表は、標準正規分布の面積を z = 0.00〜3.09 で並べた表。下側累積・上側・0 から z までの3種類があり、z = 0.00 の値と増減で見分ける。SciPy・数値積分・標準ライブラリの3つの方法で310個すべて一致した。
  • 表は z を「小数第1位まで」と「小数第2位」に分けて読む。負の z は対称性、区間は引き算、確率から z は逆引き(上位5%は 1.645)。z は (x − 平均) ÷ 標準偏差。
  • 計算では、SciPy の2つ目の引数は標準偏差(分散ではない)、離散型は pmf・連続型は pdf、上側の小さな確率は sf、範囲外の入力は nan になる点に注意する。

参考・出典

確認日はいずれも 2026年10月29日です。

  • SciPy「scipy.stats.norm」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.norm.html
  • SciPy「scipy.stats.rv_continuous」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.rv_continuous.html
  • SciPy「scipy.integrate.quad」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.quad.html
  • SciPy「scipy.stats.Normal」:https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.Normal.html
  • NumPy「numpy.histogram」:https://numpy.org/doc/stable/reference/generated/numpy.histogram.html
  • Python「statistics — 数理統計関数」NormalDist:https://docs.python.org/ja/3/library/statistics.html
  • Microsoft サポート「NORM.S.DIST 関数」:https://support.microsoft.com/ja-jp/office/norm-s-dist-関数-1e787282-3832-4520-a9ae-bd2a8d99ba88
  • Microsoft サポート「NORM.S.INV function」:https://support.microsoft.com/en-US/excel/functions/norm-s-inv-function
  • Microsoft サポート「NORM.DIST function」:https://support.microsoft.com/en-us/office/norm-dist-function-edb1cc14-a21c-4e53-839d-8082074c9f8d

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「確率密度関数とは|標準正規分布表の見方と全310値を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分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ
参加受付中

AI駆動開発、 無料セミナー