均一な分布(ほとんどの乱数ジェネレーターが生成する0.0から1.0など)を正規分布に変換するにはどうすればよいですか?選択した平均と標準偏差が必要な場合はどうなりますか?
Zigguratアルゴリズム はこのために非常に効率的ですが、 Box-Muller変換 はゼロから実装する方が簡単です(とてつもなく遅くありません)。
たくさんの方法があります:
関数の分布を別の関数に変更するには、目的の関数の逆関数を使用する必要があります。
言い換えれば、特定の確率関数を目指している場合、p(x)積分することで分布を取得します-> d(x) =積分(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))
に等しいほぼ正規分布の出力が得られます( wikipediaを参照)その最後の分布の均一分布 )
n = 10の場合、半分の速度が得られます。タイラーズソリューションの半分以上を使用したい場合(正規分布の wikipediaエントリに記載されているように )
8年後にこれに何かを追加できるのは信じられないようですが、Javaの場合、読者に Random.nextGaussian() メソッド、平均0.0および標準偏差1.0のガウス分布を生成します。
単純な加算および/または乗算により、ニーズに合わせて平均値と標準偏差が変更されます。
Box-Mullerを使用します。これに関する2つのこと:
標準のPythonライブラリモジュールrandomはあなたが望むものを持っています:
normalvariate(mu、sigma)
正規分布。 muは平均で、sigmaは標準偏差です。
アルゴリズム自体については、Pythonライブラリのrandom.pyの関数をご覧ください。
ここで、R1、R2は一様な乱数です:
SDが1の通常の分布:sqrt(-2 * log(R1))* cos(2 * pi * R2)
これは正確です...遅いループをすべて行う必要はありません!
Q一様分布(ほとんどの乱数ジェネレーターが生成する、たとえば0.0と1.0の間)を正規分布に変換するにはどうすればよいですか?
ソフトウェアの実装については、[0,1]の疑似一様ランダムシーケンスを与えるカップルランダムジェネレーター名を知っています(Mersenne Twister、Linear Congruate Generator)。それをU(x)と呼びましょう
確率論と呼ばれる数学的領域が存在します。まず、r.vをモデル化する場合。積分分布Fを使用すると、F ^ -1(U(x))を評価するだけで済みます。理論では、そのようなr.v.積分分布Fを持ちます。
ステップ2は、F ^ -1を問題なく分析的に導出できる場合、カウント方法を使用せずにr.v.〜Fを生成するために適用できます。 (例:exp.distribution)
正規分布をモデル化するには、y1 * cos(y2)を計算できます。ここで、y1〜はin [0,2pi]で一様です。 y2はrelei分布です。
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
_
histfit(randn_box_muller(10000000),100);
を呼び出すと、これが結果になります。
Matlabの組み込みの randn と比較すると、明らかに非効率的です。
私はおそらく役立つかもしれない次のコードを持っています:
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
Excelでこれを試してみてください:=norminv(Rand();0;1)
。これにより、平均がゼロで分散が統一された正規分布の乱数が生成されます。 「0」には任意の値を指定できます。したがって、数値は希望する平均値になります。「1」を変更すると、入力の2乗に等しい分散が得られます。
例:=norminv(Rand();50;3)
は、MEAN = 50 VARIANCE = 9の正規分布数になります。