Tekdüzen Dağılımı Normal Dağıtıma Dönüştürme


106

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?


3
Bir dil spesifikasyonunuz var mı, yoksa bu sadece genel bir algoritma sorusu mu?
Bill the Lizard

3
Genel algoritma sorusu. Hangi dil umurumda değil. Ancak cevabın yalnızca o dilin sağladığı belirli işlevselliğe dayanmamasını tercih ederim.
Terhorst

Yanıtlar:



47

Pek çok yöntem var:

  • Do not Kutu Muller kullanın. Özellikle çok sayıda gauss sayısı çizerseniz. Box Muller, -6 ile 6 arasında sabitlenmiş bir sonuç verir (çift kesinlik varsayılarak. İşler yüzer ile daha da kötüleşir.). Ve diğer mevcut yöntemlerden gerçekten daha az etkilidir.
  • Ziggurat iyi, ancak tablo aramasına ihtiyaç duyuyor (ve önbellek boyutu sorunları nedeniyle platforma özgü bazı ince ayarlar)
  • En sevdiğim üniforma oranı, sadece birkaç ekleme / çarpma ve zamanın 1 / 50'si kadar bir log (örneğin, oraya bakın ).
  • CDF'yi evrilmesi ise verimli (ve gözden kaçan neden?), Size google araması durumunda bunun hızlı uygulamalar mevcuttur. Quasi-Random sayılar için zorunludur.

2
[-6,6] kelepçelemeden emin misiniz? Doğruysa bu oldukça önemli bir noktadır (ve wikipedia sayfasında bir not almaya değer).
redcalx

1
@locster: Bir öğretmenimin bana söylediği şey buydu (bu tür jeneratörleri inceledi ve sözüne güveniyorum). Size bir referans bulabilirim.
Alexandre C.

7
@locster: Bu istenmeyen özellik, ters CDF yöntemi tarafından da paylaşılır. Bkz. Cimat.mx/~src/prope08/randomgauss.pdf . Bu, sıfıra çok yakın bir kayan nokta numarası verme olasılığı sıfır olmayan tek tip bir RNG kullanılarak hafifletilebilir. Çoğu RNG, daha sonra [0,1] 'e eşlenen (tipik olarak 64 bit) bir tam sayı ürettikleri için bunu yapmaz. Bu, bu yöntemleri gauss değişkenlerinin kuyruklarını örneklemek için uygunsuz hale getirir (hesaplamalı finansta düşük / yüksek vuruş seçeneklerini fiyatlandırmayı düşünün).
Alexandre C.

6
@AlexandreC. İki noktada net olmak gerekirse, 64 bitlik sayılar kullanılarak kuyruklar 8,57 veya 9,41'e çıkar (günlüğü almadan önce [0,1) dönüştürmeye karşılık gelen düşük değer). [-6, 6] 'ya sabitlenmiş olsa bile, bu aralığın dışında olma şansı yaklaşık 1.98e-9'dur, bilimde bile çoğu insan için yeterince iyidir. 8.57 ve 9.41 rakamları için bu, 1.04e-17 ve 4.97e-21 olur. Bu sayılar o kadar küçüktür ki, Box Muller örneklemesi ile söz konusu sınır açısından gerçek bir gauss örneklemesi arasındaki fark neredeyse tamamen akademiktir. Daha iyisine ihtiyacınız varsa, bunlardan dördünü toplayın ve 2'ye bölün.
CrazyCasta

6
Box Muller dönüşümünü kullanmama önerisinin büyük bir kullanıcı yüzdesi için yanıltıcı olduğunu düşünüyorum. Sınırlamayı bilmek harika, ancak CrazyCasta'nın da işaret ettiği gibi, aykırı değerlere büyük ölçüde bağımlı olmayan çoğu uygulama için muhtemelen bunun için endişelenmenize gerek yok. Örnek olarak, numpy kullanarak normal bir örneklemeye güvenmişseniz , Box Muller dönüşümüne (kutupsal koordinat formu) github.com/numpy/numpy/blob/… bağlı kaldınız .
Andreas Grivas

30

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.


4
+1 Bu, çok iyi çalışan gauss değişkenleri oluşturmak için gözden kaçan bir yöntemdir. Ters CDF, bu durumda Newton yöntemi ile verimli bir şekilde hesaplanabilir (türev e ^ {- t ^ 2}), rasyonel bir kesir olarak bir başlangıç ​​yaklaşımı elde etmek kolaydır, bu nedenle 3-4 erf ve exp değerlendirmesine ihtiyacınız vardır. Gausslu bir sayı elde etmek için tam olarak bir tek tip sayı kullanmanız gereken bir durum olan yarı rasgele sayılar kullanıyorsanız, bu zorunludur.
Alexandre C.

9
Olasılık dağılımı işlevini değil, kümülatif dağılım işlevini ters çevirmeniz gerektiğini unutmayın. Alexandre bunu ima ediyor, ama bundan daha açık bir şekilde bahsetmenin zarar vermeyeceğini düşündüm - çünkü cevap PDF'yi öneriyor
ltjax

Ortalamaya göre rastgele bir yön seçmeye hazırsanız, PDF'yi kullanabilirsiniz; bunu doğru anlıyor muyum?
Mark McKenna


1
İşte SE'deki ilgili soru güzel bir açıklamayla daha genelleştirilmiş bir cevapla.
çizgi

23

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

5

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 )


1
Bu, özellikle yakın bir normal vermeyecektir ("kuyruklar" veya bitiş noktaları gerçek normal dağılıma yakın olmayacaktır). Box-Muller, diğerlerinin önerdiği gibi daha iyidir.
Peter K.

1
Box Muller'in de yanlış kuyrukları var (çift kesinlikte -6 ile 6 arasında bir sayı döndürüyor)
Alexandre C.

n = 12 (0-1 aralığındaki 12 rasgele sayının toplamı ve 6 çıkarılması) stddev = 1 ve ortalama = 0 ile sonuçlanır. Bu daha sonra herhangi bir normal dağılım oluşturmak için kullanılabilir. Sonucu istenen stddev ile çarpın ve ortalamayı ekleyin.
JerryM

3

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

  1. Yineleme başına iki değer elde edersiniz
    edersiniz Genellikle, bir değeri önbelleğe alır ve diğerini döndürürsünüz. Bir sonraki örnek çağrısında, önbelleğe alınan değeri döndürürsünüz.
  2. Box-Muller bir Z-puanı verir
    Daha sonra, Z-puanını standart sapmaya göre ölçeklendirmeniz ve normal dağılımda tam değeri elde etmek için ortalamayı eklemeniz gerekir.

Z skorunu nasıl ölçeklendirirsiniz?
Terhorst

3
ölçekli = + StdDev * zScore // ortalama size, normal (ortalama, StdDev ^ 2) verir
yoyoyoyosef

2

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!


Biri beni düzeltmeden önce ... işte bulduğum yaklaşım: (1.5- (R1 + R2 + R3)) * 1.88. Ben de severim.
Erik Aronesty

2

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.


1

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.

Elle giriş burada


2
Ne yazık ki, python'un kütüphanesi Kinderman, AJ ve Monahan, JF, "Düzgün sapmaların oranını kullanarak rasgele değişkenlerin bilgisayarla oluşturulması", ACM Trans Math Software, 3, (1977), s. 257-260'ı kullanır. Bu, tek bir değer yerine normal değeri üretmek için iki tek tip rastgele değişken kullanır, bu nedenle OP'nin istediği eşleme olarak nasıl kullanılacağı açık değildir.
Ian

1

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))
}

0

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.


0

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?

  1. 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

  2. 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ı.

  3. 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)

  4. 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.


0

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ç: Box-Muller Matlab Histfit

Matlab yerleşik randn ile karşılaştırıldığında gerçekten verimsiz olduğu açıktır .


0

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)]

0

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

-2
function distRandom(){
  do{
    x=random(DISTRIBUTION_DOMAIN);
  }while(random(DISTRIBUTION_RANGE)>=distributionFunction(x));
  return x;
}

Yine de geri dönme garantisi yok, değil mi? ;-)
Peter K.

5
Rastgele sayılar, şansa bırakılamayacak kadar önemlidir.
Drew Noakes

Soruyu cevaplamıyor - normal dağılımın sonsuz bir alanı var.
Matt
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.