it-swarm-tr.com

Düzgün bir dağılımın normal bir dağılıma dönüştürülmesi

Tek tip bir dağılımı (çoğu rasgele sayı üreticisinin ürettiği gibi, örneğin 0.0 ile 1.0 arasında) normal bir dağılıma nasıl dönüştürebilirim? Ya seçimimde ortalama ve standart bir sapma istersem?

91
Terhorst

Ziggurat algoritması bunun için oldukça verimlidir, ancak Box-Muller dönüşümünün sıfırdan başlaması daha kolaydır (ve çılgınca değil).

46
Tyler

Çok fazla yöntem var:

  • Değil Box Muller'ı kullanın. Özellikle çok sayıda Gauss rakamı çizerseniz. Kutu Muller -6 ile 6 arasında kelepçelenen bir sonuç verir (çift hassasiyet varsayalım. Yüzenle kötüleşen şeyler.). Ve gerçekten diğer mevcut yöntemlerden daha az verimlidir.
  • Ziggurat gayet iyi, ancak masaya bakmak gerekiyor (ve önbellek boyutu sorunları nedeniyle platforma özel ince ayarlamalar)
  • Üniforma oranı benim favorimdir, sadece birkaç toplama/çarpma ve zamanın 1/50'si oranında bir log (örn. şuna bak ).
  • CDF'i is verimli (ve göz ardı edilmiş, neden?) CD'sini ters çevirdiğinizde, google'da arama yaparsanız hızlı bir şekilde uygulayabilirsiniz. Yarı-Rastgele sayılar için zorunludur.
38
Alexandre C.

Herhangi bir işlevin dağılımını diğerine değiştirmek istediğiniz işlevin tersini kullanmayı gerektirir.

Başka bir deyişle, belirli bir olasılık fonksiyonunu p(x) hedefliyorsanız, bunun üzerine bütünleşerek dağılımı elde edersiniz -> d(x) = integral (p (x)) ve tersini kullanırsınız : Inv (d (x)). Şimdi (eşit dağılım gösteren) rasgele olasılık fonksiyonunu kullanın ve sonuç değerini Inv (d (x)) fonksiyonundan kullanın. Seçtiğiniz işleve göre dağılımda rastgele değerler elde etmelisiniz.

Bu, genel matematik yaklaşımıdır - onu kullanarak, şimdi ters veya iyi bir ters yaklaşım olduğu sürece sahip olabileceğiniz herhangi bir olasılık veya dağılım işlevini seçebilirsiniz.

Umarım bu yardımcı oldu ve olasılıkla değil dağılımın kullanılmasıyla ilgili küçük yorum için teşekkür ederiz.

25
Adi

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 */
}
20
user5084

Merkezi limit teoremini kullanın wikipedia girişimathworld girişi .

Tekdüze dağılımlı sayılardan n üret, onları topla, n * 0,5 çıkar ve ortalama olarak 0'a eşit ve normalde (1/12) * (1/sqrt(N)) değerine eşit varyans çıktısına sahipsin (bkz. üniforma dağılımları sonuncusu için wikipedia)

n = 10 size yarı hızlı bir şey verir. Yarısından daha iyi bir şey istiyorsanız, tylers çözümü için gidin ( 'de belirtildiği gibi normal dağılımlara wikipedia girişi )

5
jilles de wit

Sekiz yıl sonra buna bir şeyler ekleyebilmem inanılmaz görünüyor, ancak Java için okuyucuyu ortalama 0.0 ve standart sapma ile Gauss dağılımını üreten Random.nextGaussian () yöntemine yönlendirmek istiyorum. 1.0 sizin için.

Basit bir ekleme ve/veya çarpma, ihtiyaçlarınıza göre ortalama ve standart sapmayı değiştirecektir.

1
Pepijn Schmitz

Box-Muller'ı kullanırdım. Bununla ilgili iki şey:

  1. Her yineleme için iki değer ile bitirdiniz
    Genellikle, bir değeri önbelleğe alır ve diğerini döndürürsünüz. Bir örnek için bir sonraki çağrıda, önbelleğe alınmış değeri döndürürsünüz.
  2. Box-Muller Z puanı verir
    Z-skorunu standart sapma ile ölçeklendirmeniz ve normal dağılımdaki tam değeri elde etmek için ortalamayı eklemeniz gerekir.
1
hughdbrown

Standart Python kütüphane modülü random istediğinizi var:

normal değişken (mu, sigma)
Normal dağılım. mu ortalamasıdır ve sigma standart sapmadır.

Algoritmanın kendisi için Python kütüphanesinde random.py içindeki fonksiyona bir göz atın.

Manuel giriş burada

1

R1, R2 rastgele tekdüze sayılardır:

NORMAL DAĞITIM, 1 SD: ile sqrt (-2 * log (R1))

Bu kesin ... tüm bu yavaş döngüleri yapmanıza gerek yok!

1
Erik Aronesty

• Tek tip bir dağılımı (çoğu rasgele sayı üreticisinin ürettiği gibi, örneğin 0.0 ile 1.0 arasında) normal bir dağılıma nasıl dönüştürebilirim?

  1. Yazılım uygulaması için, size [0,1] 'de bir yalancı tekdüze rastgele sıra veren çift rastgele jeneratör ismini biliyorum (Mersenne Twister, Linear Congruate Generator). Diyelim ki U (x)

  2. Olasılık teorisi denilen matematiksel alan var. İlk şey: Eğer r.v. integral dağılım F ile sonra sadece F ^ -1 (U (x)) değerlendirmeyi deneyebilirsiniz. Preory'de böyle bir r.v. ayrılmaz dağılım F. olacak.

  3. Aşama 2, F ^ -1 problemsiz analitik olarak türetilebildiği zaman herhangi bir sayma yönteminin kullanımı olmadan r.v. ~ F üretilebilir. (ör. exp.distribution)

  4. Normal dağılımı modellemek için y1 * cos (y2) 'yi hesaplayabilirsiniz, y1 ~ [0,2pi] ile aynıdır. ve y2, relei dağılımıdır.

S: Seçimimde ortalama ve standart bir sapma istersem ne olur?

Sigma * N (0,1) + m değerini hesaplayabilirsiniz.

Böyle bir kayma ve ölçeklenmenin N (m, sigma) 'ya yol açtığı gösterilebilir.

0
bruziuz

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 histfit(randn_box_muller(10000000),100);'yi çağırmak sonuçtur:  Box-Muller Matlab Histfit

Açıkçası, Matlab yerleşik randn ile karşılaştırıldığında gerçekten yetersiz.

0
madx

Yardımcı olabilecek aşağıdaki kod var:

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 rastgele bir sayı üreteci yazmaktan daha hızlı olduğu için uygulanan işlev rnorm () yöntemini kullanmak daha kolaydır. Kanıt olarak aşağıdaki kodu inceleyin

n <- length(z)
t0 <- Sys.time()
z <- rnorm(n)
t1 <- Sys.time()
t1-t0
0

Bunu Excel'de denemeniz gereken bir şey: =norminv(Rand();0;1). Bu, normalde sıfır ortalama ile birleştirilmiş ve varyansı birleştiren rasgele sayıları üretecektir. "0", herhangi bir değerle sağlanabilir, böylece sayılar istenen ortalama olur ve "1" değiştirilerek, girişinizin karesine eşit bir sapma elde edilir.

Örneğin: =norminv(Rand();50;3), MEAN = 50 VARIANCE = 9 olan normal dağılmış sayıları verir.

0
Hippo