一様乱数を用いて、ある確率分布に従う乱数を得る手法の1つ、逆関数法を見ていきます。
逆関数法の直感的説明
イメージは図のとおりです。からサンプリングしたいが、その手段がないとします。はの累積分布関数です。したがって、取る値の範囲は]です。は区間]の一様分布とし、いま、がサンプリングできたとします。ここで、紫の線で示すようにの逆関数によってが得られます。そしてこのはに従って分布する、というものです。サンプリングしたい関数から累積分布関数を求め、さらにその逆関数が定まればサンプリングができるはずです。数学的な背景はなくとも直感的にもそんな気はします。確率密度が高いところで累積分布関数の傾きも大きくなるので、よりサンプリングされやすく、逆に確率密度の低いところでは累積分布関数の傾きは小さいのでサンプリングされにくくなります。ちなみに図のは正規分布ですが、はフリーハンドで書いているので適当です、、。
証明
比較的簡単です。 区間]の一様分布に従う確率変数をとします。逆関数によってが得られるとします。このが、を累積分布関数に持つ確率分布に従っていてほしいのです。そこで任意の実数に対して、がどのように表せるのかを確認します。はつまり累積分布関数ですから、これがであってほしいわけです。さて、でしたから、
です。
そして、上図より、はと置き換えられますから、
です。(累積分布関数は単調増加関数のため、大小が入れ替わることはありません)
ここで、が]の一様分布に従うとき、以下が成り立ちます。
確率変数が以下の確率は、一様分布ならです。例えばとすれば、一様分布が0.5以下を取る確率は0.5ですよね。この関係を用いれば、式(2)の右辺は、
と書けます。以上より、
となり、知りたかった累積分布関数はであることがわかりました。累積分布関数と確率分布は1対1ですから、つまりはを累積分布関数に持つ確率分布に従っているといえます。
サンプリング実験
早速試してみます。サンプリングしたい確率分布をの指数分布とすると、その累積分布関数を求め、
これをについて解けば
です。一様分布からをサンプリングし、式(8)で変換すれば指数分布が求められるということです。試してみたところ、以下のグラフのようになり、確かに指数分布からサンプリングできていることが確認できました。
今回のコードです。
# 逆関数法 import numpy as np import matplotlib.pyplot as plt # サンプル数 N = 1000000 x = np.random.uniform(0, 1, N) y = -np.log(1-x) x2 = np.linspace(0, 5, 100) y2 = np.exp(-x2) plt.hist(y, normed=True, bins=50, alpha=0.5) plt.plot(x2, y2) plt.xlim(0,5) plt.show()