3

平均到着率 (ラムダ) と平均サービス率 (mu) を指定してポアソン到着を生成する関数を Java で作成したいと考えています。

私の例では、1 日あたり 2.2 件のリクエスト、つまり 1 日あたり 2.2 件の到着と平均サービス時間は 108 時間です。私のプログラムは t=0 分に開始することを考慮して、t1、t2、および可能性のある t3 を含むarrivals[] を返す関数を作成したいと考えています。T1、t2、および t3 は、この到着が発生する日中の瞬間 (分単位) です。次の制限があります。

t1 < t2 < t3 < 1440 minutes (24 hours*60 minutes/hour)

t2-t1 > 108 minutes

t3-t2 > 108 minutes

t3+ 108 minutes < 1440 minutes

誰か助けてくれませんか?

ありがとうございました、

アナ

4

4 に答える 4

6

D.Knuthによって提案されたこのアルゴリズムを使用できます。

private static int getPoissonRandom(double mean) {
    Random r = new Random();
    double L = Math.exp(-mean);
    int k = 0;
    double p = 1.0;
    do {
        p = p * r.nextDouble();
        k++;
    } while (p > L);
    return k - 1;
}

これがどのように機能するかを理解するには、k回の反復後にループ条件が次のようになることに注意してください。

p 1 * p 2 * ... * p k > L

これは

-ln(p 1)/ mean -ln(p 2)/ mean ... -ln(p k)/ mean> 1

pが均一に分布している場合、-ln(p)/meanは与えられた平均で指数分布することに注意してください。ポアソン分布の確率変数は、イベント間の間隔の長さが指数分布の独立した確率変数である場合に、特定のイベントが一定の間隔内で発生する回数に等しくなります。イベント間の間隔の指数分布の平均としてポアソン分布の平均を使用するため、発生をカウントする固定内部は単位長です。したがって、ループ条件は、イベント間の間隔の長さを合計し、単位間隔を超えたかどうかをチェックします。k番目のイベントをカウントしているときに単位間隔を超えた場合、間隔内でk-1イベントが発生したため、k-1を返します。

于 2012-03-23T01:26:22.133 に答える
3

逆変換サンプリングを使用して、この解決策を見つけました。

http://preshing.com/20111007/how-to-generate-random-timings-for-a-poisson-process

拒否サンプリング アプローチを使用せず、効率的で正確です。

これは、イベント間の時間の分布が指数分布であり、パラメータ lambda が到着率であるという事実を利用しています。指数分布はラムダ exp(-ラムダ x) です。その分布から値をサンプリングし、棄却サンプリングを回避するには、累積分布関数 (CDF) を使用する方が簡単です: 1 - exp(-lambda x)。CDF は、0.0 から始まり、より大きなパラメーターで 1.0 まで成長する関数です。直感的に、イベントが発生する確率は時間の経過とともに増加します。

CDF をサンプリングし、再び拒否サンプリングを回避するには、[0,1] の間の一様乱数 U を選択し、その値を CDF の逆関数に代入する方が簡単です。 /ラムダ。Ln(0) は定義されておらず、ほとんどの乱数ジェネレーターは 0.0 を含み、1.0 を除外しているため、nextEvent = -Ln(1.0-U)/lambda を使用する方が安全です。コードでミリ秒ベースの時間/スリープ関数を使用している場合は、次を使用できます。

ダブルレート = 20.0/1000.0; // 平均して 1 秒あたり 20 回

sleep(floor(-1.0 * log(1.0 - rand()*1.0/RAND_MAX) / rate) );

于 2012-11-01T19:45:21.103 に答える
0

与えられた平均でポアソン数を生成するための単純化されたコードを次に示します。

private static int poisson(double mean) {
    int r = 0;
    double a = random.nextDouble();
    double p = Math.exp(-mean);

    while (a > p) {
        r++;
        a = a - p;
        p = p * mean / r;
    }
    return r;
}

これまたは同様のものを使用して、各期間の到着数を生成できるはずです。入力は、その期間に予想される平均到着数でなければなりません。

平均が非常に大きい場合 (たとえば 500 以上) は、代わりに正規分布で到着数を概算する必要があることに注意してください。これはより効率的であり、さらに上記のコードに固有の数値オーバーフローの問題を回避します (ある時点で Math.exp(-mean) がゼロに丸められます...おっと!)

于 2012-03-23T01:20:57.983 に答える