web-dev-qa-db-ja.com

擬似乱数ジェネレータ-指数分布

いくつかの擬似乱数を生成したいと思います。これまでは、.NetライブラリのRandom.Next(int min, int max)関数に非常に満足しています。この種類のPRNGは、均一分布 を使用することを想定していますが、 指数分布

私はC#でプログラミングしていますが、擬似コードまたはC++、Javaなどを受け入れます。

提案/コードスニペット/アルゴリズム/考えはありますか?

57
Charlie Salts

一様な乱数ジェネレーターにアクセスできるため、CDFがわかっている他のディストリビューションで配布される乱数の生成は、 inversion method を使用すると簡単です。

したがって、_[0,1)_で一様な乱数uを生成し、次にxを計算します:

x = log(1-u)/(−λ_)_、

ここで、λは指数分布のレートパラメーターです。現在、xは指数分布の乱数です。上記のlogln(自然対数)であることに注意してください。

98
Alok Singhal

サンプリングの基本定理は、希望する分布を正規化し、統合し、反転させることができれば、自由に使えると考えています。

F(x)が_[a,b]_で正規化された望ましい分布がある場合。計算する

_C(y) = \int_a^y F(x) dx
_

それを反転して_C^{-1}_を取得し、[0,1)に一様にzをスローして見つけます

_x_i = C^{-1}(z_i)
_

望ましい分布になります。


あなたの場合:F(x) = ke^{-kx}そして、あなたは_[0,infinity]_が欲しいと仮定します。我々が得る :

_C(y) = 1 - e^{-ky}
_

与えることは反転可能です

_x = -1/k  ln(1 - z)
_

for zは均一に_[0,1)_にスローされます。


しかし、率直に言って、適切にデバッグされたライブラリを使用することは、あなた自身の啓発のためにこれをしているのでなければ、より賢くなります。

13
dmckee

適切な乱数が必要な場合は、gslルーチンへのリンクを検討してください: http://www.gnu.org/software/gsl/ 。ルーチンはgsl_ran_exponential。 [0、1)に均一な分布を持つ組み込みジェネレーターを使用して乱数を生成する場合(例:u = Random.Next(0、N-1)/ N、大きなNの場合)、次を使用します:

-mu * log (1-u)

Gslソースのrandist/exponential.cを参照してください。

編集:後でいくつかの答えと比較するため-これはmu = 1/lambdaと同等です。ここでmuは分布の平均であり、OPがリンクされているウィキペディアページのスケールパラメーターとも呼ばれ、ラムダはレートパラメーターです。

6
Ramashalanka

指数分布の興味深い特性の1つは、指数到着間隔の到着プロセスを検討することです。任意の期間(t1、t2)およびその期間に到着します。これらの到着は、t1とt2の間に均一に配信されます。 (シェルドン・ロス、確率過程)。

擬似乱数ジェネレーターがあり、何らかの理由で(たとえば、ソフトウェアがログを計算できない)、上記の変換を行いたくないが、指数関数r.vが必要な場合。平均が1.0です。

あなたはできる :

1)1001 U(0,1)のランダム変数を作成します。

2)順番に並べ替え

3)1番目から2番目を減算し、2番目から3番目を減算します。

4)これらの差は、平均= 1.0の分布からの指数RVです。

あまり効率的ではないと思いますが、同じ目的のための手段です。

4
Grembo

オープンソース Dan DyerによるUncommons Mathsライブラリ は、Javaの乱数ジェネレーター、確率分布、組み合わせ論、および統計を提供します。

他の貴重なクラスの中で、ExponentialGeneratorは@Alok Singhalによって説明されたアイデアを本質的に実装しています。 そのチュートリアルブログ では、1分あたり平均10回発生したランダムイベントをシミュレートするコードスニペットが提供されています。

_final long oneMinute = 60000;
Random rng = new MersenneTwisterRNG();

// Generate events at an average rate of 10 per minute.
ExponentialGenerator gen = new ExponentialGenerator(10, rng);
boolean running = true;
while (true)
{
    long interval = Math.round(gen.nextValue() * oneMinute);
    Thread.sleep(interval);

    // Fire event here.
}
_

もちろん、時間単位_per second_(ここでは_a minute_ではなく)を使用する場合は、_final long oneMinute = 1000_を設定するだけです。

ExponentialGeneratorのメソッドnextValue()の-​​ ソースコード をさらに深く掘り下げると、いわゆる逆変換サンプリングGenerating_exponential_variates [wiki] で説明されています:

_public Double nextValue()
{
    double u;
    do
    {
        // Get a uniformly-distributed random double between
        // zero (inclusive) and 1 (exclusive)
        u = rng.nextDouble();
    } while (u == 0d); // Reject zero, u must be positive for this to work.
    return (-Math.log(u)) / rate.nextValue();
}  
_

P.S.:最近、Uncommons Mathsライブラリを使用しています。ダンダイアーに感謝します。

1
hengxin

私があなたの問題を理解し、PRNGの有限数を受け入れることができる場合、次のようなアプローチに従うことができます:

  • すべての要素が指数分布にある配列を作成します
  • PRNGを生成します。これは、配列への整数インデックスです。そのインデックスにある配列の要素を返します。
0
GreenMatt