🎓 レベル:標準 | 重要度:B(推奨)
📎 前提:逆関数法 | 関連:代表的分布の生成(正規・指数・ポアソン)
要点(BLUF)
- 変数変換法:一様乱数を関数 で変換して目的分布を作る。逆関数が書けない正規分布も、2つの一様乱数から Box–Muller 法で生成できます。
- 合成法:目的分布が「複数の分布の混合 」のとき、まず重み で成分を選び、その成分から引く。
- Box–Muller で生成した正規乱数は平均 ・標準偏差 ・2系列の相関 と、理論(0・1・0)に一致します。
1. 変数変換法
逆関数法(逆関数法)が を必要としたのに対し、変数変換法は「ある分布のサンプルを関数 で写すと別の分布になる」性質を直接使います。 の分布は、 の密度と のヤコビアンから決まります(多次元なら )。
代表がBox–Muller 法です。標準正規分布は CDF の逆が初等関数で書けないので逆関数法が使えません。そこで、独立な2つの一様乱数 から、独立な2つの標準正規 を作ります。
なぜ正規になるか(極座標の直観):2次元標準正規 を極座標 で見ると、角度 は 上の一様分布、半径の2乗 は平均2の指数分布(自由度2のカイ二乗)になります。だから 、(指数分布を逆関数法で作る)とすれば、 が2次元標準正規になる——これが Box–Muller の中身です。
import numpy as np
# 乱数シードを固定
rng = np.random.default_rng(5)
n = 500_000
u1 = rng.random(n)
u2 = rng.random(n)
radius = np.sqrt(-2 * np.log(u1)) # 半径 R
z0 = radius * np.cos(2 * np.pi * u2) # 標準正規 その1
z1 = radius * np.sin(2 * np.pi * u2) # 標準正規 その2
z = np.concatenate([z0, z1])
print(f"Box-Muller 平均 = {z.mean():.4f} (理論 0)")
print(f"Box-Muller 標準偏差 = {z.std():.4f} (理論 1)")
print(f"z0 と z1 の相関 = {np.corrcoef(z0, z1)[0,1]:.4f} (理論 0)")
出力:
Box-Muller 平均 = -0.0007 (理論 0)
Box-Muller 標準偏差 = 0.9994 (理論 1)
z0 と z1 の相関 = 0.0020 (理論 0)
出力の意味:たった2つの一様乱数から、平均 0・標準偏差 1 の標準正規が2系列ぶん生成でき、しかも2系列は無相関(相関 0.002)。逆関数が書けない正規分布を、極座標変換という変数変換で見事に回避しています。一般の正規 は でずらせます。
2. 合成法(混合分布)
合成法は、目的分布が**混合(mixture)**の形
で書けるときに使います。手順は2段:(1) 重み に従って成分 を選び、(2) 選んだ成分 からサンプルする。各成分が引きやすければ、複雑な混合分布も簡単に生成できます。
import numpy as np
# 乱数シードを固定
rng = np.random.default_rng(8)
# 0.3*N(-2,0.5^2) + 0.7*N(3,1^2) の混合
n = 400_000
w = np.array([0.3, 0.7])
mu = np.array([-2.0, 3.0])
sd = np.array([0.5, 1.0])
comp = rng.choice(2, size=n, p=w) # 成分を重みで選ぶ
x = rng.normal(mu[comp], sd[comp]) # 選んだ成分から生成
theory_mean = (w * mu).sum()
print(f"混合分布の平均(シミュ) = {x.mean():.4f}")
print(f"混合分布の平均(理論) = {theory_mean:.4f}")
print(f"成分1の割合(シミュ) = {(comp==0).mean():.4f} (目標 0.3)")
出力:
混合分布の平均(シミュ) = 1.5021
混合分布の平均(理論) = 1.5000
成分1の割合(シミュ) = 0.2998 (目標 0.3)
出力の意味:混合分布の平均 がシミュ 1.5021 と一致。成分1が選ばれた割合も 0.2998 で目標 0.3 どおり。合成法は「複雑な分布を、単純な分布の重み付き選択に分解する」発想で、後の条件付き分布からの生成とも通じます。
3. 他手法との関係
- Box–Muller は変数変換の代表ですが、三角関数が遅いので、実用では**極法(Marsaglia polar)**や Ziggurat 法(棄却法ベース)が使われます。numpy の
normal()は Ziggurat 系で高速です(代表的分布の生成(正規・指数・ポアソン))。 - 合成法は棄却法(棄却法(受理・棄却サンプリング))と組み合わせられます(各成分を棄却法で引く等)。
- 変数変換は、和(畳み込み)・比・最大値などにも一般化でき、(正規の二乗和)・・ 分布などの生成につながります。
数式の直観的意味
変数変換法は「確率を保ったまま、座標を測り直す」操作です。Box–Muller なら、平面上の正規分布を「角度(一様)×半径(指数)」という回しやすい座標に置き換え、その座標を一様・指数として作ってから直交座標に戻す。合成法は「全体の確率の山を、いくつかの小山に分け、まずどの小山かをサイコロで決めてから、その小山の中で引く」操作。どちらも「難しい分布を、作りやすい部品の組み合わせに翻訳する」という乱数生成の共通戦略の現れです。
⚠️ よくある誤解・落とし穴
- 「Box–Muller は1個の一様乱数でいい」ではない:2つ必要(半径と角度)。代わりに正規を2つ得ます。
- 「 と で同じ値が出る」ではない: は独立な別サンプル。相関はゼロ(出力で 0.002)。
- 「合成法は重みを正規化しなくていい」ではない: が必要。正規化を忘れると成分選択が狂います。
- 「変数変換は1次元だけ」ではない:多次元でもヤコビアン を使えば成立。Box–Muller は2次元変換の好例です。
- 「 で が来たら?」:理論上確率ゼロですが、実装では半開区間 を使うか の引数がゼロにならないよう配慮します(numpy の
random()は なので を取る等)。
対応シミュレーション参照
本文の Box–Muller(default_rng(5))と混合分布の合成法(default_rng(8))。
関連ノート
- 逆関数法(前提・逆が書ける分布)
- 棄却法(受理・棄却サンプリング)(関連・別の汎用変換)
- 代表的分布の生成(正規・指数・ポアソン)(次のトピック・実用ライブラリの中身)
- ギブスサンプリング(条件付き分布からの生成)
- 第2章 乱数生成 目次
- シミュレーション・モンテカルロ法 全体目次