从偏斜的正态分布中生成随机数

时间:2010-03-07 03:11:55

标签: php javascript ruby

当你在大多数语言中使用随机(最小,最大)函数时,分布是什么样的?

如果我想在20%的时间内生成一系列数字,并且在80%的时间内生成另一个数字范围,我该如何生成随后的一系列随机数呢?

ex)我应该得到随机频率,但“1”的频率必须比频率“0”高出约20%

9 个答案:

答案 0 :(得分:1)

大多数伪随机生成器内置编程语言产生 均匀分布 ,即该范围内的每个值与生成的任何其他值具有相同的概率。范围。实际上,在某些情况下,这一要求是语言标准的一部分。某些语言(如Python或R)支持各种常见发行版。

如果语言不支持,您必须使用数学技巧来制作其他发行版,例如来自统一发行版的正态发布,或者您可以查找执行此功能的第三方库。

你的问题似乎要简单得多,因为随机变量是离散 (及其更简单的类型,即二进制)。这些技巧的诀窍是在给定范围内产生一个均匀分布的随机数,比如0到999,并按照与每个值相关的比例分割这个范围,在这种情况下,这将是: / p>

  If (RandomNumber) < 200    // 20%
     RandomVariable = 0
  Else                       // 80%
     RandomVariable = 1

这个逻辑当然可以应用于n个离散变量。

答案 1 :(得分:1)

对于大多数语言,生成的随机数可能取决于该语言中的算法,也可能是基于时间,处理器,种子数等几个因素随机生成的。

分布不正常。事实上,如果函数返回5个整数,则所有5个整数都很有可能出现在下一个函数调用中。这也称为统一分布。

所以说如果你希望在20%的时间内产生一个数字(比如7),而在80%的时间内产生另一个数字(比如13),你可以这样做一个数组:

var arr = [7,13,13,13,13];
var picked = arr[Math.floor(Math.random()*arr.length)] ; 
// since Math.random() returns a float from 0.0 to 1.0
因此,7有20%的机会出现,13有80%的机会。

答案 2 :(得分:1)

这是一种可能的方法:

ranges = [(10..15), (20..30)]
selector = [0, 0, 1,1,1,1,1,1,1,1] # 80:20 distribution array

# now select a range randomly    
random_within_range(ranges(selector[random(10)]))  


def random_within_range range
  rand (range.last - range.begin - (range.exclude_end? ? 1 : 0)) + range.begin
end

答案 3 :(得分:1)

您的问题与您的示例有很大不同。所以我会回答这两个问题,你可以找出你真正想要的答案。

1)你的例子(我不知道ruby或java,所以忍受我)

  • 首先从0到1的均匀分布生成一个随机数,我们称之为X。
  • 然后您可以设置if / else(即if(x <.2){1} else {0})

2)从具有偏斜的正态分布生成随机数

  • 您可以查看偏斜的分布,例如偏向学生T的分布具有高度自由度。
  • 你也可以使用正常的CDF,只需选择那样的数字。
  • 这是一个paper,讨论如何使用统一分布中的多个随机数进行此操作
  • 最后,您可以使用非参数方法,这将涉及内核密度估计(我怀疑您不会寻找任何复杂的东西)。

答案 4 :(得分:1)

就像任何人说的那样,大多数语言中的伪随机数生成器实现了(0,1)上的均匀分布。 如果你有两个响应类别(0,1),p概率为1,你有一个伯努利分布,可以用

模拟
#  returns 1 with p probability and 0 with (1-p) probability
def bernoulli(p)
rand()<p ? 1:0;
end

这很简单。 倾斜的正态分布是完全不同的野兽,由正常分布的pdf和cdf的'联合'产生,以产生偏斜。你可以阅读Azzalini的作品here。使用gem分布,您可以使用

生成概率密度函数
# require 'distribution'
def sn_pdf(x,alpha)
sp = 2*Distribution::Normal.pdf(x)*Distribution::Normal.cdf(x*alpha)
end

获得cdf很困难,因为没有分析解决方案,所以你应该整合。 要从偏斜法线中获取随机数,可以使用acceptation-rejection算法。

答案 5 :(得分:0)

大多数计算机语言对其(伪)随机整数生成器均匀分布。所以每个整数都有可能。

对于您的示例,假设您想要“1”55%的时间和“0”45%的时间。

要使这些频率不相等,请尝试生成1到100之间的随机数。如果生成的数字是1到55,则输出“1”;否则输出“0”。

答案 6 :(得分:0)

怎么样

var oneFreq = 80.0/100.0;
var output = 0;
if (Math.random() > oneFreq)
   output = 1;

或者,如果您希望20%的值介于0和100之间,80%介于100和200之间。

var oneFreq = 80.0/100.0;
var oneRange  = 100;
var zeroRange = 100;
var output = Math.random();
if (output > oneFreq)
   output = zeroRange + Math.floor(oneRange * (output - oneFreq));
else
   output = Math.floor(zeroRange * output);

答案 7 :(得分:0)

在红宝石中,我会这样做:

class DistributedRandom
  def initialize(left, right = nil)
    if right
      @distribution = [0] * left + [1] * right
    else
      @distribution = left
    end
  end
  def get
    @distribution[rand @distribution.length]
  end
end

使用80:20分发运行测试:

test = [0,0]
rnd = DistributedRandom.new 80, 20   # 80:20 distribution
10000.times { test[rnd.get] += 1 }; puts "Test 1", test

在右侧运行20%以上分布的测试:

test = [0,0]
rnd = DistributedRandom.new 100, 120   # +20% distribution
10000.times { test[rnd.get] += 1 }; puts "Test 2", test

使用具有超过91个离散值的三角函数的自定义分布运行测试,但输出不适合以前的测试:

test = [0,0]
rnd = DistributedRandom.new((0..90).map {|x| Math.sin(Math::PI * x / 180.0)})
10000.times { test[rnd.get] += 1 }; puts "Test 3", test

答案 8 :(得分:-1)

如果您想要一个良好的数学理解,请查看this lecture