8

A = 1 と B = 10 の間で各数値の確率が異なる乱数を生成するにはどうすればよいですか?

例: 数 / 確率

1 - 20%

2 - 20%

3 - 10%

4 - 5%

5 - 5%

...等々。

残念ながら、A = 1000 と B = 100000 など、より大きな範囲では役に立たないハードコードされた回避策をいくつか知っています。

私たちが持っていると仮定します

    Rand()

乱数Rを返すメソッド、0 < R < 1、これを行う適切な方法でコードサンプルを投稿できますか? c# / Java / actionscript で好ましい。

4

6 に答える 6

7

100 個の整数の配列を作成し、20 個の 1、20 個の 2、10 個の 3、5 個の 4、5 個の 5 などを入力します。次に、配列から項目をランダムに選択します。

int[] numbers = new int[100];
// populate the first 20 with the value '1'
for (int i = 0; i < 20; ++i)
{
    numbers[i] = 1;
}
// populate the rest of the array as desired.

// To get an item:
// Since your Rand() function returns 0 < R < 1
int ix = (int)(Rand() * 100);
int num = numbers[ix];

これは、アイテムの数が適度に少なく、精度が厳しすぎない場合にうまく機能します。つまり、4.375% の 7 が必要な場合は、はるかに大きな配列が必要になります。

于 2012-11-29T22:54:33.037 に答える
5

クヌースがAJウォーカーに帰したエレガントなアルゴリズムがあります(Electronics Letters 10、8(1974)、127-128;ACMTrans。MathSoftware3(1977)、253-256)。

アイデアは、n個の異なる色の合計k * n個のボールがある場合、コンテナ番号が次のようにn個のコンテナにボールを分散させることができるということです。私は色iと多くても1つの他の色のボールを含んでいます。証明はnの帰納法によるものです。誘導ステップでは、ボールの数が最も少ない色を選択します。

あなたの例では、n =10です。確率に適切なmを掛けて、すべて整数になるようにします。したがって、おそらくm = 100で、色0のボールが20個、色1のボールが20個、色2のボールが10個、色3のボールが5個などです。つまり、k=10です。

次に、次元nのテーブルを生成します。各エントリは、確率(色iと他の色のボールの比率)と他の色です。

ランダムなボールを生成するには、[0、n)の範囲でランダムな浮動小数点数rを生成します。iを整数部分(rの床)とし、xを超過分(r – i)とします。

if (x < table[i].probability) output i
else output table[i].other

このアルゴリズムには、ランダムなボールごとに1回だけ比較するという利点があります。

例を考えてみましょう(Knuthと同じ)。

サイコロを投げるシミュレーションを検討してください。

したがって、P(2)= 1/36、P(3)= 2/36、P(4)= 3/36、P(5)= 4/36、P(6)= 5/36、P(7) = 6/36、P(8)= 5/36、P(9)= 4/36、P(10)= 3/36、P(11)= 2/36、P(12)=1/36。

36 * 11を掛けると、393個のボール、色2の11、色3の22、色4の33、…、色12の11が得られます。k= 393/11=36です。

Table [2] =(11/36、カラー4)

テーブル[12]=(11/36、カラー10)

表[3]=(22/36、色5)

テーブル[11]=(22/36、カラー5)

Table [4] =(8/36、カラー9)

テーブル[10]=(8/36、カラー6)

テーブル[5]=(16/36、カラー6)

テーブル[9]=(16/36、カラー8)

Table [6] =(7/36、カラー8)

Table [8] =(6/36、カラー7)

Table [7] =(36/36、カラー7)

于 2012-11-30T00:03:39.743 に答える
2

p(n)乱数の望ましい確率を与える関数があると仮定します。

r = rand()  // a random number between 0 and 1
for i in A to B do
    if r < p(i) 
      return i
    r = r - p(i)    
done

より高速な方法は、(B - A) * 100 要素の配列を作成し、配列内で発生する各項目の数と配列のサイズの比率がその確率になるように、A から B までの数値を入力することです。次に、一様乱数を生成して配列のインデックスを取得し、配列に直接アクセスして乱数を取得できます。

于 2012-11-29T22:07:41.567 に答える
1

確率に従って、一様乱数の結果を必要な出力にマッピングします。

たとえば、あなたの例では:

If `0 <= Round() <= 0.2`: result = 1.
If `0.2 < Round() <= 0.4`: result = 2.
If `0.4 < Round() <= 0.5`: result = 3.
If `0.5 < Round() <= 0.55`: result = 4.
If `0.55 < Round() <= 0.65`: result = 5.
...
于 2012-11-29T22:06:58.590 に答える
1

これはクヌースのアルゴリズムの実装です。いくつかの回答で説明されているように、1) 合計頻度のテーブルを作成する 2) 乱数を生成する 3) 天井関数で丸める 4) 乱数が該当する「合計」範囲を見つけ、元の配列エンティティを出力するそれに基づいて

于 2015-12-29T18:29:40.503 に答える
0

逆変換

確率的に言えば、累積分布関数 F(x) は、任意のランダムに抽出された値 (X と呼びます) が <= 特定の値 x である確率を返します。たとえば、この場合に F(4) を実行すると、.6 になります。あなたの例の確率の実行中の合計は です{.2, .4, .5, .55, .6, .65, ....}。つまり、4 以下の値がランダムに得られる確率は 0.6 です。しかし、私が実際に知りたいのは、累積確率関数の関数、F_inv です。累積確率が与えられたときの x の値を知りたいです。F_inv(.6) を渡して 4 を返したい。これが逆変換法と呼ばれる理由です。

したがって、逆変換法では、基本的に累積分布の中で、ランダムな Uniform (0,1) 数が該当する区間を見つけようとしています。これは、perreal と icepack が投稿したアルゴリズムに当てはまります。累積分布関数の観点からそれを述べる別の方法は次のとおりです。

Generate a random number U
for x in A .. B
   if U <= F(x) then return x 

ループを B から A に移動させ、U >= F(x) であるかどうかを確認する方が効率的である可能性があることに注意してください。小さい確率が分布の最初に来る場合

于 2012-11-30T05:38:42.243 に答える