从偏态正态分布生成随机数

4

当你在大多数编程语言中使用random(min,max)函数时,它的分布是怎样的?

如果我想要产生20%时间内的一组数字和80%时间内的另一组数字,我该如何生成符合这种要求的随机数序列呢?

例如:我应该获得随机频率,但是“1”的频率必须比“0”的频率高约20%。

9个回答

1

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

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

就是这么简单。 偏态正态分布是一种完全不同的东西,由正态分布的概率密度函数和累积分布函数“联合”而成,以此来创造偏斜。你可以在Azzalini的作品这里中阅读相关内容。使用gem分布,您可以生成概率密度函数,其中

# require 'distribution'
def sn_pdf(x,alpha)
sp = 2*Distribution::Normal.pdf(x)*Distribution::Normal.cdf(x*alpha)
end

获取累积分布函数很困难,因为没有解析解,所以您需要进行积分。 要从偏斜正态分布中获取随机数,可以使用接受-拒绝算法。


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%。


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

1
大多数编程语言内置的伪随机生成器会产生均匀分布,即范围内的每个值被生成的概率相同。实际上,在某些情况下,这种要求是语言标准的一部分。一些语言,如Python或R,支持各种常见的分布。
如果语言不支持它,您可以使用数学技巧从均匀分布中产生其他分布,例如正态分布,或者您可以寻找执行此功能的第三方库。
然而,您的问题似乎更简单,因为随机变量是离散的(且属于较简单的类型,即二进制)。对于这些情况,技巧是在给定范围内(例如0到999)从均匀分布中产生随机数,并按与每个值相关联的比例分割该范围,在本例中可能是以下内容:
  If (RandomNumber) < 200    // 20%
     RandomVariable = 0
  Else                       // 80%
     RandomVariable = 1

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


1

你的问题与示例有很大不同。因此,我将回答两个问题,你可以找出哪个是你真正想要的答案。

1)你的示例(我不知道Ruby或Java,所以请容忍我)

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

2)生成带偏斜的正态分布的随机数

  • 您可以研究偏态分布,例如自由度高的偏态学生T分布。
  • 您也可以使用正态CDF,然后以此方式挑选数字。
  • 这里有一篇论文,讨论如何使用来自均匀分布的多个随机数来完成此操作。
  • 最后,您可以使用非参数方法,其中包括核密度估计(但我怀疑您不会寻找任何这么复杂的东西)。

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

0
在 Ruby 中,我会这样做:
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

0
大多数计算机语言的(伪)随机整数生成器都具有均匀分布。因此,每个整数具有相等的概率。
对于你的示例,假设你想要 55% 的时间输出 "1",45% 的时间输出 "0"。
为了得到这些不平等的频率,可以尝试生成一个介于 1 到 100 之间的随机数。如果生成的数字在 1 到 55 之间,则输出 "1";否则输出 "0"。

1
PS:一个“正常”的分布并不等同于一个均匀分布。 - Peter K.

-1
如果你想要更好的数学理解,可以看一下这个讲座

链接已失效,相关性未得到解释。 - Victor Axelsson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接