web-dev-qa-db-ja.com

合計がMであるN個の乱数を取得する

合計が値であるN個の乱数を取得します。

たとえば、合計が1になる5つの乱数が必要だとします。

次に、有効な可能性は次のとおりです。

0.2 0.2 0.2 0.2 0.2

別の可能性は:

0.8 0.1 0.03 0.03 0.04

等々。これは、ファジーC平均の持ち物の行列を作成するために必要です。

43
marionmaiden

短い答え:

N個の乱数を生成し、それらの合計を計算し、それぞれを合計で割り、Mを掛けるだけです。

長い回答:

上記の解決策はnotを実行し、これらの乱数が何に使用されるかに応じて問題になる可能性がある均一な分布をもたらします。 Matti Virkkunenによって提案された別の方法:

0と1の間のN-1個の乱数を生成します。0と1自体をリストに追加し、それらを並べ替えて、隣接する数値の差異を取得します。

これが均一な分布をもたらすかどうかはわかりません

56
Guillaume

0と1の間のN-1個の乱数を生成します。0と1自体をリストに追加し、それらを並べ替えて、隣接する数値の差異を取得します。

43
Matti Virkkunen

現在受け入れられている答え は均一な分布を与えないことに注意する価値があると思います:

「N個の乱数を生成し、それらの合計を計算し、それぞれを合計で除算する」

これを確認するために、N = 2とM = 1の場合を見てみましょう。これは、(0,1)の範囲でxを均一に選択することでリスト[x、1-x]を生成できるため、取るに足らないケースです。提案されたソリューションはペア[x /(x + y)、y /(x + y)]を生成します。ここで、xとyは(0,1)で均一です。これを分析するには、0 <z <0.5となるzを選択し、最初の要素がzより小さい確率を計算します。分布が均一である場合、この確率はzになるはずです。ただし、

確率(x /(x + y)<z)=確率(x <z(x + y))=確率(x(1-z)<zy)=確率(x <y(z/(1-z))) = z /(2-2z).

私はいくつかの簡単な計算を行いましたが、これまでのところ均一分布をもたらすための唯一の解決策は Matti Virkkunenによって提案された のようです:

「0と1の間のN-1の乱数を生成し、0と1自体をリストに追加し、それらを並べ替えて、隣接する数の差をとります。」

26
Accipitridae

Javaの場合:

private static double[] randSum(int n, double m) {
    Random Rand = new Random();
    double randNums[] = new double[n], sum = 0;

    for (int i = 0; i < randNums.length; i++) {
        randNums[i] = Rand.nextDouble();
        sum += randNums[i];
    }

    for (int i = 0; i < randNums.length; i++) {
        randNums[i] /= sum * m;
    }

    return randNums;
}
4
Vortico

残念ながら、一様な乱数が必要な場合、ここでの回答の多くは正しくありません。一様な乱数を保証する最も簡単な(そして多くの言語で最も速い)ソリューションは、

# This is Python, but most languages support the Dirichlet.
import numpy as np
np.random.dirichlet(np.ones(n))*m

ここで、nは生成する乱数の数で、mは結果の配列の合計です。このアプローチは正の値を生成し、合計が1になる有効な確率(m = 1とする)を生成する場合に特に役立ちます。

3
cgnorthcutt

N個の乱数を生成し、それらの合計を計算し、それぞれを合計で割ります。

Guillaumeの受け入れられた回答を拡張 、ここにJava正確にそれを行う関数があります。

_public static double[] getRandDistArray(int n, double m)
{
    double randArray[] = new double[n];
    double sum = 0;

    // Generate n random numbers
    for (int i = 0; i < randArray.length; i++)
    {
        randArray[i] = Math.random();
        sum += randArray[i];
    }

    // Normalize sum to m
    for (int i = 0; i < randArray.length; i++)
    {
        randArray[i] /= sum;
        randArray[i] *= m;
    }
    return randArray;
}
_

テスト実行で、getRandDistArray(5, 1.0)は以下を返しました。

_[0.38106150346121903, 0.18099632814238079, 0.17275044310377025, 0.01732932296660358, 0.24786240232602647]
_
2
Stevoisiak

この問題ディリクレ分布 で乱数を生成する問題と同等です。合計が正の数MになるN個の正の数を生成するには、可能な各組み合わせが等しく可能性があります。

  • N個の指数分布乱数を生成します。このような数値を生成する1つの方法は、次のように書くことができます。

    _number = -ln(1.0 - RNDU())
    _

    ここで、ln(x)xの自然対数であり、RNDU()は0以上1未満の乱数を返すメソッドです(たとえば、JavaScriptのMath.random())。乱数の組み合わせの偏った分布が生じるため、一様分布でこれらの数を生成することは理想的ではないことに注意してください。

  • この方法で生成された数値を合計で割ります。
  • 各数値にMを掛けます。

結果は、合計がMにほぼ等しいディリクレ分布のN個の数値です(丸め誤差のため、「ほぼ」と言います)。

この問題は N次元シンプレックスから一様に乱数を生成する の問題とも同等です。

2
Peter O.
  1. N-1個の乱数を生成します。
  2. 上記の数値の合計を計算します。
  3. 計算された合計と目的の合計の差をセットに追加します。

これでN個の乱数が得られ、それらの合計が目的の合計になります。

1
Yuval

あなたは制約について少しスリムです。たくさんの手順がうまくいきます。

たとえば、数値は正規分布していますか?ユニフォーム?
私はすべての数値が正で、平均値M/Nの周りに均一に分布している必要があると思います。

これを試して。

  1. 平均= M/N。
  2. 0と2 * meanの間のN-1値を生成します。これは0〜1の標準的な数値にすることができます、ランダムな値は(2 * u-1)*であり、適切な範囲の値を作成することを意味します。
  3. N-1個の値の合計を計算します。
  4. 残りの値はN和です。
  5. 残りの値が制約(0〜2 *平均)に適合しない場合は、手順を繰り返します。
0
S.Lott