it-swarm-id.com

Mengubah Distribusi yang Seragam menjadi Distribusi Normal

Bagaimana saya bisa mengubah distribusi yang seragam (karena kebanyakan generator angka acak menghasilkan, misalnya antara 0,0 dan 1,0) menjadi distribusi normal? Bagaimana jika saya menginginkan deviasi standar dan standar yang saya pilih?

91
Terhorst

Algoritma Ziggurat cukup efisien untuk ini, meskipun Box-Muller mentransformasikan lebih mudah diimplementasikan dari awal (dan tidak gila lambat).

46
Tyler

Ada banyak metode:

  • Jangan tidak menggunakan Box Muller. Apalagi jika Anda menggambar banyak angka gaussian. Box Muller menghasilkan hasil yang dijepit antara -6 dan 6 (dengan asumsi presisi ganda. Hal-hal memburuk dengan mengapung.). Dan itu benar-benar kurang efisien daripada metode lain yang tersedia.
  • Ziggurat baik-baik saja, tetapi membutuhkan pencarian tabel (dan beberapa penyesuaian platform khusus karena masalah ukuran cache)
  • Rasio seragam adalah favorit saya, hanya beberapa tambahan/perkalian dan log 1/50 dari waktu (mis. lihat di sana ).
  • Menghindari CDF adalah efisien (dan diabaikan, mengapa?), Anda memiliki implementasi cepat yang tersedia jika Anda mencari di google. Ini wajib untuk nomor Kuasi-Acak.
38
Alexandre C.

Mengubah distribusi fungsi apa pun ke yang lain melibatkan penggunaan kebalikan dari fungsi yang Anda inginkan.

Dengan kata lain, jika Anda bertujuan untuk fungsi probabilitas spesifik p(x) Anda mendapatkan distribusi dengan mengintegrasikannya -> d(x) = integral (p (x)) dan menggunakan kebalikannya : Inv (d (x)). Sekarang gunakan fungsi probabilitas acak (yang memiliki distribusi seragam) dan berikan nilai hasil melalui fungsi Inv (d (x)). Anda harus mendapatkan nilai acak yang dilemparkan dengan distribusi sesuai dengan fungsi yang Anda pilih.

Ini adalah pendekatan matematika umum - dengan menggunakannya Anda sekarang dapat memilih probabilitas atau fungsi distribusi yang Anda miliki selama memiliki pendekatan invers atau invers yang baik.

Semoga ini bisa membantu dan terima kasih atas komentar kecil tentang menggunakan distribusi dan bukan probabilitas itu sendiri.

25
Adi

Berikut ini adalah implementasi javascript menggunakan bentuk kutub dari transformasi Box-Muller.

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

Gunakan teorema limit pusat entri wikipediaentri mathworld untuk keuntungan Anda.

Hasilkan n dari angka-angka yang terdistribusi secara seragam, jumlahkan, kurangi n * 0,5 dan Anda memiliki output dari distribusi yang mendekati normal dengan rata-rata sama dengan 0 dan varians sama dengan (1/12) * (1/sqrt(N)) (lihat wikipedia tentang distribusi seragam untuk yang terakhir) 

n = 10 memberi Anda sesuatu yang setengah cepat layak. Jika Anda menginginkan sesuatu yang lebih dari setengah layak untuk solusi tylers (seperti yang tercantum dalam entri wikipedia pada distribusi normal )

5
jilles de wit

Tampaknya luar biasa bahwa saya dapat menambahkan sesuatu ke ini setelah delapan tahun, tetapi untuk kasus Jawa saya ingin mengarahkan pembaca ke metode Random.nextGaussian () , yang menghasilkan distribusi Gaussian dengan mean 0,0 dan standar deviasi 1.0 untuk Anda.

Penambahan dan/atau perkalian sederhana akan mengubah mean dan standar deviasi untuk kebutuhan Anda.

1
Pepijn Schmitz

Saya akan menggunakan Box-Muller. Dua hal tentang ini:

  1. Anda berakhir dengan dua nilai per iterasi
    Biasanya, Anda menyimpan satu nilai dan mengembalikan yang lainnya. Pada panggilan berikutnya untuk sampel, Anda mengembalikan nilai yang di-cache.
  2. Box-Muller memberikan skor-Z
    Anda harus kemudian menskalakan skor-Z dengan deviasi standar dan menambahkan nilai rata-rata untuk mendapatkan nilai penuh dalam distribusi normal.
1
hughdbrown

Modul perpustakaan Python standar acak memiliki apa yang Anda inginkan:

normalvariate (mu, sigma)
Distribusi normal. mu adalah mean, dan sigma adalah standar deviasi.

Untuk algoritme itu sendiri, lihat fungsi di random.py di pustaka Python.

Entri manual ada di sini

1

Di mana R1, R2 adalah angka seragam acak:

DISTRIBUSI NORMAL, dengan SD 1: sqrt (-2 * log (R1)) * cos (2 * pi * R2)

Ini tepat ... tidak perlu melakukan semua loop lambat itu!

1
Erik Aronesty

T Bagaimana saya bisa mengubah distribusi yang seragam (seperti yang dihasilkan oleh kebanyakan generator bilangan acak, mis. Antara 0,0 dan 1,0) menjadi distribusi normal?

  1. Untuk implementasi perangkat lunak saya tahu beberapa nama generator acak yang memberikan Anda urutan acak seragam semu di [0,1] (Mersenne Twister, Linear Congruate Generator). Sebut saja U (x)

  2. Ada bidang matematika yang disebut teori probabilitas. Hal pertama: Jika Anda ingin memodelkan r.v. dengan distribusi integral F maka Anda dapat mencoba hanya untuk mengevaluasi F ^ -1 (U (x)). Dalam teori, terbukti bahwa r.v. akan memiliki distribusi integral F.

  3. Langkah 2 dapat diterapkan untuk menghasilkan r.v. ~ F tanpa menggunakan metode penghitungan apa pun ketika F ^ -1 dapat diturunkan secara analitis tanpa masalah. (mis. exp.distribution)

  4. Untuk memodelkan distribusi normal, Anda dapat menghitung y1 * cos (y2), di mana y1 ~ seragam dalam [0,2pi]. dan y2 adalah distribusi relei.

T: Bagaimana jika saya ingin deviasi yang berarti dan standar yang saya pilih?

Anda dapat menghitung sigma * N (0,1) + m.

Dapat ditunjukkan bahwa pergeseran dan penskalaan seperti itu mengarah ke N (m, sigma)

0
bruziuz

Ini adalah implementasi Matlab menggunakan bentuk kutub dari Box-Muller transformasi:

Fungsi 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

Dan menjalankan histfit(randn_box_muller(10000000),100); ini hasilnya:  Box-Muller Matlab Histfit

Jelas itu sangat tidak efisien dibandingkan dengan Matlab built-in randn .

0
madx

Saya memiliki kode berikut yang mungkin dapat membantu:

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

Juga lebih mudah untuk menggunakan fungsi yang diimplementasikan rnorm () karena lebih cepat daripada menulis generator angka acak untuk distribusi normal. Lihat kode berikut sebagai buktinya

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

Saya kira Anda harus mencoba ini di Excel: =norminv(Rand();0;1). Ini akan menghasilkan angka acak yang harus didistribusikan secara normal dengan nol mean dan menyatukan varians. "0" dapat diberikan dengan nilai apa pun, sehingga angka-angka itu akan menjadi rata-rata yang diinginkan, dan dengan mengubah "1", Anda akan mendapatkan varians yang sama dengan kuadrat input Anda.

Sebagai contoh: =norminv(Rand();50;3) akan menghasilkan angka yang terdistribusi normal dengan MEAN = 50 VARIANCE = 9.

0
Hippo