どのようにして(ほとんどの乱数ジェネレータが生成するように、たとえば0.0と1.0の間で)均一分布を正規分布に変換できますか?選択した平均値と標準偏差が必要な場合はどうなりますか?
どのようにして(ほとんどの乱数ジェネレータが生成するように、たとえば0.0と1.0の間で)均一分布を正規分布に変換できますか?選択した平均値と標準偏差が必要な場合はどうなりますか?
回答:
ジッグラトアルゴリズムがあるが、このためにかなり効率的であるボックス・ミュラー変換を最初から実装が簡単(と遅いクレイジーではない)です。
たくさんの方法があります:
関数の分布を別の関数に変更するには、必要な関数の逆を使用する必要があります。
言い換えると、特定の確率関数p(x)を目指す場合、それを積分して分布を得る-> d(x)= integral(p(x))とその逆を使用:Inv(d(x)) 。次に、ランダムな確率関数(一様分布)を使用し、関数Inv(d(x))を使用して結果値をキャストします。選択した関数に応じて、ランダムな値が分布でキャストされるはずです。
これは一般的な数学のアプローチです。これを使用することで、逆近似または良好な逆近似がある限り、任意の確率または分布関数を選択できるようになります。
これが役に立ったといいのですが、確率そのものではなく分布の使用についての小さな発言に感謝します。
以下は、Box-Muller変換の極形式を使用したjavascript実装です。
/*
* Returns member of set with a given mean and standard deviation
* mean: mean
* standard deviation: std_dev
*/
function createMemberInNormalDistribution(mean,std_dev){
return mean + (gaussRandom()*std_dev);
}
/*
* Returns random number in normal distribution centering on 0.
* ~95% of numbers returned should fall between -2 and 2
* ie within two standard deviations
*/
function gaussRandom() {
var u = 2*Math.random()-1;
var v = 2*Math.random()-1;
var r = u*u + v*v;
/*if outside interval [0,1] start over*/
if(r == 0 || r >= 1) return gaussRandom();
var c = Math.sqrt(-2*Math.log(r)/r);
return u*c;
/* todo: optimize this algorithm by caching (v*c)
* and returning next time gaussRandom() is called.
* left out for simplicity */
}
中心極限定理のウィキペディアエントリ mathworldエントリを利用してください。
均一に分布した数のnを生成し、それらを合計し、n * 0.5を引くと、平均が0で分散が等しいほぼ正規分布の出力が得られます(1/12) * (1/sqrt(N))
(最後の分布については、ウィキペディアを参照してください)。
n = 10を指定すると、速度が半分ほど速くなります。半分以上のものが必要な場合は、タイラーソリューションを使用してください(正規分布のWikipediaのエントリに記載されています)。
Box-Mullerを使用します。これに関する2つのこと:
ここで、R1、R2はランダムで一様な数です。
SDが1の通常の分布:sqrt(-2 * log(R1))* cos(2 * pi * R2)
これは正確です...これらすべての遅いループを実行する必要はありません!
8年後にこれに何かを追加できるとは信じられないようですが、Javaの場合は、読者に平均0.0と標準偏差1.0のガウス分布を生成するRandom.nextGaussian()メソッドを紹介したいと思います。
単純な加算または乗算、あるいはその両方により、平均と標準偏差がニーズに変わります。
標準のPythonライブラリモジュールrandomには、次のような機能があります。
normalvariate(mu、sigma)
正規分布。muは平均、sigmaは標準偏差です。
アルゴリズム自体については、Pythonライブラリのrandom.pyの関数をご覧ください。
これは、Donald Knuthの著書The Art of Computer Programmingのセクション3.4.1からのアルゴリズムP(通常の逸脱のためのPolarメソッド)の私のJavaScript実装です。
function normal_random(mean,stddev)
{
var V1
var V2
var S
do{
var U1 = Math.random() // return uniform distributed in [0,1[
var U2 = Math.random()
V1 = 2*U1-1
V2 = 2*U2-1
S = V1*V1+V2*V2
}while(S >= 1)
if(S===0) return 0
return mean+stddev*(V1*Math.sqrt(-2*Math.log(S)/S))
}
Qどのようにして均一分布(ほとんどの乱数ジェネレータが生成する、たとえば0.0と1.0の間)を正規分布に変換できますか?
ソフトウェアの実装では、[0,1](Mersenne Twister、Linear Congruate Generator)で疑似均一ランダムシーケンスを提供するいくつかのランダムジェネレーター名を知っています。それをU(x)としましょう
確率論と呼ばれる数学的領域が存在します。最初に、積分分布Fを使用してrvをモデル化する場合は、F ^ -1(U(x))を評価してみてください。理論では、そのようなrvが積分分布Fを持つことが証明されました。
ステップ2は、F ^ -1が問題なく分析的に導出できる場合、カウント方法を使用せずにrv〜Fを生成するために適用できます。(例:分布)
正規分布をモデル化するには、y1 * cos(y2)を計算します。ここで、y1〜は[0,2pi]で均一です。y2はレリー分布です。
Q:選択した平均と標準偏差が必要な場合はどうなりますか?
sigma * N(0,1)+ mを計算できます。
そのようなシフトとスケーリングがN(m、sigma)につながることを示すことができます
これは、Box-Muller変換の極形式を使用したMatlab実装です。
機能randn_box_muller.m
:
function [values] = randn_box_muller(n, mean, std_dev)
if nargin == 1
mean = 0;
std_dev = 1;
end
r = gaussRandomN(n);
values = r.*std_dev - mean;
end
function [values] = gaussRandomN(n)
[u, v, r] = gaussRandomNValid(n);
c = sqrt(-2*log(r)./r);
values = u.*c;
end
function [u, v, r] = gaussRandomNValid(n)
r = zeros(n, 1);
u = zeros(n, 1);
v = zeros(n, 1);
filter = r==0 | r>=1;
% if outside interval [0,1] start over
while n ~= 0
u(filter) = 2*rand(n, 1)-1;
v(filter) = 2*rand(n, 1)-1;
r(filter) = u(filter).*u(filter) + v(filter).*v(filter);
filter = r==0 | r>=1;
n = size(r(filter),1);
end
end
私はおそらく助けることができる次のコードを持っています:
set.seed(123)
n <- 1000
u <- runif(n) #creates U
x <- -log(u)
y <- runif(n, max=u*sqrt((2*exp(1))/pi)) #create Y
z <- ifelse (y < dnorm(x)/2, -x, NA)
z <- ifelse ((y > dnorm(x)/2) & (y < dnorm(x)), x, z)
z <- z[!is.na(z)]
また、正規分布用の乱数ジェネレーターを作成するよりも高速なので、実装された関数rnorm()を使用する方が簡単です。証明として次のコードを参照してください
n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
function distRandom(){
do{
x=random(DISTRIBUTION_DOMAIN);
}while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
return x;
}