在ruby中生成正态分布随机数的代码是什么?
(注意:我回答了我自己的问题,但我会等几天才接受是否有人有更好的答案。)
修改
搜索到这一点,我查看了两次搜索产生的所有SO页面:
+“正态分布”红宝石
和
+高斯+随机红宝石
答案 0 :(得分:48)
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
在法律允许的范围内,antonakos已放弃RandomGaussian
Ruby类的所有版权及相关或相邻权利。这项工作发表于:丹麦。
许可声明并不意味着我关心此代码。相反,我没有使用代码,我没有测试它,我也不用Ruby编程。
答案 1 :(得分:19)
原始问题要求代码,但作者的后续评论意味着对使用现有库感兴趣。我对此感兴趣,我的搜索出现了这两个红宝石:
gsl - “与GNU Scientific Library的Ruby接口”(要求您安装GSL)。具有均值= 0和给定标准差的正态分布随机数的调用序列是
rng = GSL::Rng.alloc
rng.gaussian(sd) # a single random sample
rng.gaussian(sd, 100) # 100 random samples
rubystats - “来自PHPMath的统计库的一个端口”(纯ruby)。具有给定均值和标准差的正态分布随机数的调用序列是
gen = Rubystats::NormalDistribution.new(mean, sd)
gen.rng # a single random sample
gen.rng(100) # 100 random samples
答案 2 :(得分:11)
+1 @ antonakos的答案。这是我一直在使用的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 = !@compute_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 :)。
答案 3 :(得分:10)
另一种选择,这个使用distribution宝石,由一个SciRuby研究员编写。
我认为使用起来有点简单。
require 'distribution'
normal = Distribution::Normal.rng(1)
norm_distribution = 1_000.times.map {normal.call}