指数衰减式随机分布和连续分布的离散化

时间:2010-11-05 17:41:42

标签: c++ math probability random

遗憾的是,尽管在范围内使用了统一的整数,但我在编程中使用随机数并不是很有经验。因此,我不得不对这个话题提出疑问。

问题1(更具体):

我正在寻找一种方法来根据类似于“指数衰减”http://en.wikipedia.org/wiki/Exponential_decay)曲线的概率分布来选择数组元素(动态大小,但已知)。 含义:我想更喜欢选择第一个元素而不是其他元素。我想要一个单调递减函数(在降低之前不会像许多众所周知的概率分布那样增长,如伽马分布)。

也许几何分布是我可以使用的东西?但后来我需要回答我关于将此分布扩展到数组索引的第二个问题。

当然,选择最后一个元素而不是第一个元素的双重方法也可以。

问题2(更一般): 在任何实现中是否有一个概念可以将任何连续随机分布扩展到给定的数组范围(包括离散化)?

示例:使用高斯正态分布,结果始终是某个数组中的有效索引(意思是:首选中间元素)。

这个(link text)可能是我想要使用的吗?

平台和库: 我正在使用 C ++ 进行编程并且目前使用 boost :: random 库(link text),但我愿意使用类似于 gsl library 或其他质量库。

还有一个愿望: 我更喜欢使用一些质量库而不是一些快速和脏的custom_functions。

谢谢!

5 个答案:

答案 0 :(得分:4)

一般规则是在统一分布中选择您的数字,然后应用函数将它们转换为您想要的分布。您应用的函数是您希望随机数落入的函数的反函数。

如果你想要以f(x)成比例的方式挑选随机数,那么你从统一分布中选择一个随机数u,然后应用f ^ -1(u),这就是你的新数字。

因此,如果您希望以与exp(-x)成比例的概率选择随机数,则选择均匀分布的随机数并取其ln:

double x=ln(rand()); 

应该给出概率分布为exp(-x)的随机数。

注意:我并不是说rand()是一个很好的功能,你需要研究好的随机数生成器的细节。但假设您有一个好的随机数生成器,这是一个很好的解决方案。

编辑:忘了一个减号:

double x=-ln(rand()); 

是正确的答案。

答案 1 :(得分:2)

Q1)您正在寻找的是exponential distribution。 Boost库附带exponential distribution generator

Q2)这听起来像是要创建histogram。在您的站点示例中,设置数组中间区域的区域,以表示更接近您从分布中绘制的正常随机值的平均值的元素。如果您没有足够的关于分配性质的信息,您将需要从感兴趣的分布中收集代表性样本并将其存储在另一个阵列中。使用样本的最小值和最大值,然后可以创建另一个数组来计算每个箱中有多少采样元素。合理的经验法则是,如果你有n个样本,你应该有sqrt(n)个bin。

更新:正如Tryer正确指出的那样,如果在创建直方图之前没有将分布的元素保存到第二个数组中,则需要找到一些处理元素的方法,这些元素不属于已建立的bin。

答案 2 :(得分:2)

你的Q2:“例子:使用高斯正态分布,结果总是某个数组中的有效索引(意思是:中间元素是首选)。”

除非我误解,否则这不是真的。正态分布后的随机变量理论上可以取范围内的值(-infinity,infinity)。因此,除非您截断异常值并强制使用落在外部的随机变量值,比如+/- 3标准差与+/- 3标准差值,否则您无法强制将正态分布强制到有限网格上。 / p>

答案 3 :(得分:1)

我认为将这个问题分成两步是一个很好的起点。首先,如果你有一个离散的概率分布,那么从这个分布中提取的问题并不是那么糟糕。随机提升有这样做的方法。向下滚动此page到加权骰子示例。它将从给定的概率分布返回一个整数。您可以使用此整数从您感兴趣的数组中选择元素。

问题的第二部分是如何从像exponential这样的连续概率分布转变为离散分布,就像在boost示例中使用的那样。有几种方法你可以去这里,但因为你说你想要曲线“喜欢”指数衰减,我会尝试解释一个快速而简单的实现我们正在牺牲一些统计严谨性。

这里的想法是从一组离散点的连续分布中进行采样,然后调整这些点(标准化),使它们总和为1。下面是针对指数分布执行此操作的代码。

double expDist(int x, double lambda)  
{
   return(lambda*exp(-lambda*x));
}

//code to sample from this distribution
int i,numElements //where numElements has the number of elements in the array you wish to draw from.
vector<double> output;
double sum,temp
sum=0;
for(i=0;i<numElements;i++)
{
   temp=expDist(i,0.5);  //substitute any value you want for lambda in the second argument
   output.push_back(temp); 
   sum+=temp;
}
//after having sampled at all the points we need to divide each element in the array by the variable sum so that the sum of the values in the array is equal to 1 and thus a valid probability distribution
for(i=0;i<numElements;i++)
{
   output[i]/=sum;
}

然后,您可以将输出变量提供给boost库中的加权骰子示例,它应该符合您的需要。这种离散采样的一般方法然后归一化矢量可以适用于许多不同类型的分布。

答案 4 :(得分:1)

我认为你寻找指数分布,因为指数分布假定无界数量的元素,因此会产生序列最后一个元素的偏差

适合您的问题的是Beta distribution,其中alpha&lt; 1和beta&gt; 1。