web-dev-qa-db-ja.com

正規分布に基づく範囲内の乱数

範囲(nからm、たとえば100から150)の乱数を生成したいのですが、純粋にランダムではなく、正規分布に基づいた結果が必要です。

これは、一般的に、125前後の数値を「クラスター化」したいという意味です。

必要なものがたくさんあるように見えるこの乱数パッケージを見つけました: http://codeproject.com/KB/recipes/Random.aspx

さまざまなランダムジェネレーター(mersieneツイスターを含む)をサポートし、ジェネレーターをディストリビューションに適用できます。

しかし、私が正規分布ジェネレーターを使用する場合、乱数はおよそ-6から+8までです(実際の範囲はfloat.minからfloat.maxです)。

それを必要な範囲にどのようにスケーリングしますか?

34
ConfusedAgain

標準正規分布の平均は0、標準偏差は1です。平均mと偏差sの分布を作成する場合は、単にsを掛けてから、mを追加します。正規分布は理論的には無限であるため、範囲にハードキャップを設定することはできません。 (100から150)範囲外の数値を明示的に拒否することなく、偏差を適切に選択することで、(たとえば)数値の99%が範囲内にあることを保証できます。

人口の約99.7%は+/- 3標準偏差内にあるので、あなたが自分のものを約(25/3)、うまくいくはずです。

したがって、次のようなものが必要です:(normal * 8.333) + 125

27
tzaman

興味を引くために、均一なRNGから正規分布の乱数を生成するのは非常に簡単です(ただし、ペアで実行する必要があります)。

_Random rng = new Random();
double r = Math.Sqrt(-2 * Math.Log(rng.NextDouble()));
double θ = 2 * Math.Pi * rng.NextDouble();
double x = r * Math.Cos(θ);
double y = r * Math.Sin(θ);
_

xyには、平均0と分散1の2つの独立した正規分布の乱数が含まれるようになりました。必要に応じてスケーリングおよび変換して、必要な範囲を取得できます(interjayが説明します)。


説明:

このメソッドは Box–Muller変換 と呼ばれます。これは、密度値自体p = exp(-r^2/2)が_0_と_1_の間で均一に分布するという2次元単位ガウスの特性を使用します(簡単にするために正規化定数は削除されています)。

均一なRNGを使用してこのような値を簡単に生成できるため、半径r = sqrt(-2 * log(p))の円形の輪郭になります。次に、_0_と_2*pi_の間に2番目の一様確率変数を生成して、円形の輪郭上の一意の点を定義する角度_θ_を与えることができます。最後に、極座標_(r, θ)_からデカルト座標_(x, y)_に変換することにより、2つの i.i.d。 正規ランダム変量を生成できます。

pが均一に分布しているというこのプロパティは、他の次元には当てはまりません。そのため、一度に2つの正規変量を正確に生成する必要があります。

14
Will Vousden

tzamanの答えは正しいですが、リンクしたライブラリを使用する場合は、自分で計算を実行するよりも簡単な方法があります。NormalDistributionオブジェクトには書き込み可能なプロパティMu(平均を意味する)とSigma (標準偏差)。したがって、tzamanの数値を使用して、Muを125に設定し、Sigmaを8.333に設定します。

4
interjay

これはニーズに対して単純すぎるかもしれませんが、中心に向かって重み付けされた分布で乱数を取得するための迅速で安価な方法は、2つ(またはそれ以上)の乱数を追加することです。

2つの6面サイコロを振って追加するときを考えてみてください。ほとんどの場合、合計は7、6と8、5と9などであり、2または12になることはめったにありません。

2
dkamins

これは、Sin/Cosを計算する必要がなく、Piを知る必要もない他のアルゴリズムです。理論的背景については聞かないでください。私はそれをどこかで一度見つけました、そしてそれは私がそれ以来使っているものです。 @WillVousdenが言及しているのと同じBox-Muller変換のある種の正規化だと思います。また、ペアで結果を生成します。

例はVBscriptです。他の言語に変換するのに十分簡単です。

Sub calcRandomGauss (byref y1, byref y2)
    Dim x1, x2, w
    Do
        x1 = 2.0 * Rnd() - 1.0
        x2 = 2.0 * Rnd() - 1.0
        w = x1 * x1 + x2 * x2
    Loop While w >= 1.0 Or w = 0  'edited this line, thanks Richard

    w = Sqr((-2.0 * Log(w)) / w )
    y1 = x1 * w
    y2 = x2 * w
End Sub
0
mgr326639

この問題への別のアプローチでは、ベータ分布(正規分布とは異なり、ハードレンジがあります)を使用し、次のような適切なパラメーターを選択する必要があります。分布には、指定された平均と標準偏差(分散の平方根)があります。 この質問 を参照してください。

0
Peter O.