2011-04-28 177 views
26

在ruby中生成正態分佈隨機數的代碼是什麼?Ruby中生成高斯(正態分佈)隨機數的代碼

(注:我回答我自己的問題,但接受,看看是否有人有一個更好的答案之前,我會等待幾天。)

編輯:

搜索此,我看着所有網頁上,來自這兩個搜索這樣造成:

+「正態分佈」紅寶石

+高斯+隨機紅寶石

+0

檢查相關的問題(見右側面板)? – Gumbo 2011-04-28 22:19:56

+0

是的,我查了一下,雖然有些地方有算法,但沒有人用Ruby編碼它。這是一個常見的任務,它確實應該在標準庫中。但是如果沒有這樣做,我認爲StackOverflow上應該可以找到複製粘貼代碼。 – Eponymous 2011-04-28 22:26:18

+0

提一下你所查的內容可能是一個好主意,這樣思考回答的人就不會檢查他們,除非他們認爲你錯過了某些東西。 – 2011-04-28 23:34:27

回答

43

Python的random.gauss()和Boost的normal_distribution都使用Box-Muller transform,所以對於Ruby來說也應該足夠好。

def gaussian(mean, stddev, rand) 
    theta = 2 * Math::PI * rand.call 
    rho = Math.sqrt(-2 * Math.log(1 - rand.call)) 
    scale = stddev * rho 
    x = mean + scale * Math.cos(theta) 
    y = mean + scale * Math.sin(theta) 
    return x, y 
end 

該方法可以封裝在一個類中,該類可以逐個返回樣本。

class RandomGaussian 
    def initialize(mean, stddev, rand_helper = lambda { Kernel.rand }) 
    @rand_helper = rand_helper 
    @mean = mean 
    @stddev = stddev 
    @valid = false 
    @next = 0 
    end 

    def rand 
    if @valid then 
     @valid = false 
     return @next 
    else 
     @valid = true 
     x, y = self.class.gaussian(@mean, @stddev, @rand_helper) 
     @next = y 
     return x 
    end 
    end 

    private 
    def self.gaussian(mean, stddev, rand) 
    theta = 2 * Math::PI * rand.call 
    rho = Math.sqrt(-2 * Math.log(1 - rand.call)) 
    scale = stddev * rho 
    x = mean + scale * Math.cos(theta) 
    y = mean + scale * Math.sin(theta) 
    return x, y 
    end 
end 

CC0(CC0)

下法律允許的範圍內,antonakos已放棄所有版權及相關或鄰接權的RandomGaussian Ruby類。這項工作發表於:丹麥。


許可證聲明並不意味着我關心此代碼。相反,我不使用代碼,我沒有測試它,並且我不用Ruby編程。

+0

您可以爲您的代碼添加許可許可證(BSD/CC-0或其他)(因爲它旨在用於粘貼重用​​) – Eponymous 2011-05-31 20:57:28

+4

@同名完成。 – antonakos 2011-06-01 16:41:38

+2

只提供給sig塊;) – drewish 2013-11-26 19:31:40

19

原始問題要求提供代碼,但作者的後續評論意味着使用現有庫的興趣。我對同樣的感興趣,我的搜索發現了這兩個寶石:

gsl - 「Ruby接口到GNU科學圖書館」(需要你安裝GSL)。對於均值= 0和給定的標準偏差的正態分佈的隨機數的調用序列是

rng = GSL::Rng.alloc 
rng.gaussian(sd)  # a single random sample 
rng.gaussian(sd, 100) # 100 random samples 

rubystats - 「從PHPMath統計庫的端口」(純紅寶石)。具有給定均值和標準差的正態分佈隨機數的呼叫順序爲

gen = Rubystats::NormalDistribution.new(mean, sd) 
gen.rng    # a single random sample 
gen.rng(100)   # 100 random samples 
10

@ antonakos的回答+1。以下是我一直使用的Box-Muller的實現;它本質上是相同的,但略有收緊代碼:

class RandomGaussian 
    def initialize(mean = 0.0, sd = 1.0, rng = lambda { Kernel.rand }) 
    @mean, @sd, @rng = mean, sd, rng 
    @compute_next_pair = false 
    end 

    def rand 
    if (@compute_next_pair = [email protected]_next_pair) 
     # Compute a pair of random values with normal distribution. 
     # See http://en.wikipedia.org/wiki/Box-Muller_transform 
     theta = 2 * Math::PI * @rng.call 
     scale = @sd * Math.sqrt(-2 * Math.log(1 - @rng.call)) 
     @g1 = @mean + scale * Math.sin(theta) 
     @g0 = @mean + scale * Math.cos(theta) 
    else 
     @g1 
    end 
    end 
end 

當然,如果你真的關心速度,你應該實現Ziggurat Algorithm :)。

8

另一種選擇,這一個使用distribution寶石,由一個SciRuby研究員編寫。

我覺得使用起來有點簡單。

require 'distribution' 
normal = Distribution::Normal.rng(1) 
norm_distribution = 1_000.times.map {normal.call} 
+0

看着這段代碼,我不知道預期的標準偏差應該是什麼。 – 2013-12-10 20:10:03

+1

轉到此處:http://rubydoc.info/gems/distribution/0.7.0/Distribution/Normal/Ruby_ 您會看到rng(1)指定了平均值,並且您可以指定標準偏差你想通過傳遞額外的參數'Distribution :: Normal.rng(mean,standard_deviation)'來調用該分配中的隨機值。 – Ryanmt 2013-12-19 20:24:32

+0

正確的鏈接是:[distribution](https://rubygems.org/gems/distribution) – pisaruk 2014-11-15 19:26:14