Düzgün bir dağılımı (çoğu rasgele sayı üreticisinin ürettiği gibi, ör. 0,0 ile 1,0 arasında) normal dağılıma nasıl dönüştürebilirim? Ya seçimimden bir ortalama ve standart sapma istiyorsam?
Düzgün bir dağılımı (çoğu rasgele sayı üreticisinin ürettiği gibi, ör. 0,0 ile 1,0 arasında) normal dağılıma nasıl dönüştürebilirim? Ya seçimimden bir ortalama ve standart sapma istiyorsam?
Yanıtlar:
Ziggurat algoritması rağmen, bu oldukça verimlidir Box-Muller dönüşümü sıfırdan uygulanması daha kolay (ve yavaş deli değil) 'dir.
Pek çok yöntem var:
Herhangi bir işlevin dağılımını diğerine değiştirmek, istediğiniz işlevin tersini kullanmayı içerir.
Başka bir deyişle, belirli bir olasılık fonksiyonu olan p (x) 'i hedeflerseniz, dağılımı onun üzerinden integral alarak elde edersiniz -> d (x) = integral (p (x)) ve tersini kullanırsınız: Inv (d (x)) . Şimdi (tekdüze dağılıma sahip olan) rastgele olasılık işlevini kullanın ve sonuç değerini Inv (d (x)) işlevi aracılığıyla dökün. Seçtiğiniz işleve göre dağılımla atılmış rastgele değerler almalısınız.
Bu genel matematik yaklaşımıdır - bunu kullanarak, ters veya iyi ters yaklaşıma sahip olduğu sürece sahip olduğunuz herhangi bir olasılık veya dağılım fonksiyonunu artık seçebilirsiniz.
Umarım bu yardımcı olur ve olasılığın kendisi değil, dağıtımın kullanılması hakkındaki küçük yorum için teşekkür ederiz.
Box-Muller dönüşümünün kutupsal formunu kullanan bir javascript uygulaması.
/*
* 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 */
}
Merkezi limit teoremini kullanın wikipedia girişi mathworld girişi kullanın.
Düzgün dağıtılmış sayıların n'sini oluşturun, toplayın, n * 0.5'i çıkarın ve ortalama 0'a eşit ve varyansa eşit olan yaklaşık normal dağılımın çıktısına sahip olursunuz (1/12) * (1/sqrt(N))
( sonuncusu için tekdüze dağılımlar hakkındaki Wikipedia'ya bakın )
n = 10 size yarı hızlı bir şey verir. Yarısından daha iyi bir şey istiyorsanız, tylers çözümüne gidin ( normal dağıtımlarla ilgili wikipedia girişinde belirtildiği gibi )
Box-Muller kullanırım. Bununla ilgili iki şey:
R1, R2 rastgele tek tip sayılardır:
NORMAL DAĞILIM, 1 SD ile: sqrt (-2 * log (R1)) * cos (2 * pi * R2)
Bu kesin ... tüm bu yavaş döngüleri yapmaya gerek yok!
Sekiz yıl sonra buna bir şeyler ekleyebilmem inanılmaz görünüyor, ancak Java için okuyucuları sizin için ortalama 0.0 ve standart sapma 1.0 ile bir Gauss dağılımı oluşturan Random.nextGaussian () yöntemine yönlendirmek istiyorum.
Basit bir toplama ve / veya çarpma, ihtiyaçlarınıza göre ortalama ve standart sapmayı değiştirecektir.
Standart Python kitaplık modülü rastgele istediğiniz şeye sahiptir:
normal değişken (mu, sigma)
Normal dağılım. mu ortalamadır ve sigma standart sapmadır.
Algoritmanın kendisi için, Python kütüphanesinde random.py içindeki işleve bir göz atın.
Bu, Donald Knuth'un The Art of Computer Programming kitabının 3.4.1. Bölümünden Algoritma P'nin ( normal sapmalar için Polar yöntemi ) JavaScript uygulamam :
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))
}
Bunu EXCEL'de denemeniz gerektiğini düşünüyorum: =norminv(rand();0;1)
. Bu, normal olarak sıfır ortalamayla dağıtılması gereken rastgele sayıları ve varyansı birleştirir. "0" herhangi bir değerle sağlanabilir, böylece sayılar istenen ortalama değerde olur ve "1" i değiştirerek, girişinizin karesine eşit varyansı elde edersiniz.
Örneğin: =norminv(rand();50;3)
ORTALAMA = 50 VARIANCE = 9 ile normal dağıtılan sayıları verir.
S Düzgün bir dağılımı (çoğu rasgele sayı üreticisinin ürettiği gibi, ör. 0,0 ile 1,0 arasında) normal dağılıma nasıl dönüştürebilirim?
Yazılım uygulaması için [0,1] 'de (Mersenne Twister, Linear Congruate Generator) sözde tekdüze bir rasgele dizi veren çift rastgele oluşturucu isimlerini biliyorum. U (x) diyelim
Olasılık teorisi denen matematiksel alan var. İlk şey: Eğer rv'yi F integral dağılımı ile modellemek istiyorsanız, o zaman sadece F ^ -1 (U (x)) 'yi değerlendirmeyi deneyebilirsiniz. Pr. Teoride, böyle bir rv'nin F integral dağılımına sahip olacağı kanıtlandı.
Adım 2, F ^ -1'in problemsiz analitik olarak türetilebildiği durumda, herhangi bir sayma yöntemi kullanılmadan rv ~ F oluşturmak için uygulanabilir. (ör. exp.distribution)
Normal dağılımı modellemek için y1 * cos (y2) 'yi hesaplayabilirsiniz, burada y1 ~ [0,2pi]' de tek tiptir. ve y2, releasei dağılımıdır.
S: Seçimimden bir ortalama ve standart sapma istiyorsam ne olur?
Sigma * N (0,1) + m'yi hesaplayabilirsiniz.
Bu tür bir kayma ve ölçeklemenin N (m, sigma) 'ya yol açtığı gösterilebilir.
Bu, Box-Muller dönüşümünün kutupsal formunu kullanan bir Matlab uygulamasıdır :
İşlev 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
Ve bunu çağırmak histfit(randn_box_muller(10000000),100);
sonuç:
Matlab yerleşik randn ile karşılaştırıldığında gerçekten verimsiz olduğu açıktır .
Yardımcı olabilecek aşağıdaki koda sahibim:
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)]
Normal dağılım için bir rastgele sayı üreteci yazmaktan daha hızlı olduğundan, uygulanan rnorm () işlevini kullanmak da daha kolaydır. Kanıtlamak için aşağıdaki koda bakın
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;
}