稳定分布的随机数
本文关键字:随机数 分布 | 更新日期: 2023-09-27 18:25:07
如何在C#中生成具有稳定分布的随机数?Random类具有均匀分布。上的许多其他代码互联网呈现正态分布。但我们需要稳定的分布意思是无限方差,又称肥尾分布。
原因是为了产生现实的股票价格。在现实中在世界范围内,价格的巨大变化比正态分布。
有人知道转换Random类输出的C#代码吗稳定分布?
编辑:嗯。准确的分布比确保它随机产生至少20西格玛这样的巨大西格玛更不重要。我们想测试一种交易策略在真正的胖尾分布中的弹性,这正是股市价格的表现。
我刚刚读到关于ZipFian和Cauchy的评论。既然我必须选择,让我们使用柯西分布,但我也会尝试ZipFian进行比较。
通常情况下,方法为:
-
选择一个稳定的肥尾分布。比如说,柯西分布。
-
查找所选分布的分位数函数。
对于柯西分布,这将是p --> peak + scale * tan( pi * (p - 0.5) )
。
- 现在你有了一种将均匀分布随机数转换为柯西分布随机数的方法
有道理吗?参见
http://en.wikipedia.org/wiki/Inverse_transform_sampling
详细信息。
卡维特:我已经很久没有学统计学了。
更新:
我非常喜欢这个问题,我只是在博客上写了它:见
http://ericlippert.com/2012/02/21/generating-random-non-uniform-data/
我的文章探讨了Zipfian分布的几个有趣的例子:
http://blogs.msdn.com/b/ericlippert/archive/2010/12/07/10100227.aspx
如果您有兴趣使用Zipfian分布(通常在科学或社会领域建模过程时使用),您可以按照以下方式进行操作:
- 为分布选择k(偏斜)
- 预先计算累积分布的域(这只是一个优化)
- 通过查找域中最近的值来生成分布的随机值
样本代码:
List<int> domain = Enumerable.Range(0,1000); // generate your domain
double skew = 0.37; // select a skew appropriate to your domain
double sigma = domain.Aggregate(0.0d, (z,x) => x + 1.0 / Math.Pow(z+1, skew));
List<double> cummDist = domain.Select(
x => domain.Aggregate(0.0d, (z,y) => z + 1.0/Math.Pow(y, skew) * sigma));
现在,您可以通过从域中选择最接近的值来生成随机值:
Random rand = new Random();
double seek = rand.NextDouble();
int searchIndex = cummDist.BinarySearch(seek);
// return the index of the closest value from the distribution domain
return searchIndex < 0 ? (~searchIndex)-1 : searchIndex-1;
当然,您可以通过从映射并返回该域值的过程中分解出具体化分布域的逻辑来概括整个过程。
我面前有James Gentle关于这个主题的Springer卷,随机数生成和蒙特卡罗方法,这是我的统计学家妻子提供的。它在第105页讨论了稳定家族:
稳定分布族是一个通常重尾分布的灵活族。该族包括一个参数的一个极值处的正态分布和另一个极值的柯西分布。Chambers、Mallows和Stuck(1976)给出了一种产生偏离稳定分布的方法。(注意辅助函数D2中常数的一些错误,用于计算(ex-1)/x。)它们的方法在IMSL库中使用。对于对称稳定分布,Devroye(1986)指出,通过利用对称稳定与Fejer de la Vallee-Poissin分布的关系,可以开发出一种更快的方法。Buckle(1995)展示了如何根据数据模拟稳定分布的参数。
很难产生偏离一般稳定分布的情况。如果你需要这样做,那么我建议你使用IMSL这样的库。我不建议你自己尝试。
然而,如果你在稳定族中寻找特定的分布,例如Cauchy,那么你可以使用Eric描述的方法,即概率积分变换。只要你能写出封闭形式的分布函数的逆,那么你就可以使用这种方法。
下面的C#代码生成一个随机数,该随机数遵循给定形状参数alpha
和beta
的稳定分布。我把它发布到公共领域的知识共享零。
public static double StableDist(Random rand, double alpha, double beta){
if(alpha<=0 || alpha>2 || beta<-1 || beta>1)
throw new ArgumentException();
var halfpi=Math.PI*0.5;
var unif=NextDouble(rand);
while(unif == 0.0)unif=NextDouble(rand);
unif=(unif - 0.5) * Math.PI;
// Cauchy special case
if(alpha==1 && beta==0)
return Math.Tan(unif);
var expo=-Math.Log(1.0 - NextDouble(rand));
var c=Math.Cos(unif);
if(alpha == 1){
var s=Math.Sin(unif);
return 2.0*((unif*beta+halfpi)*s/c -
beta * Math.Log(halfpi*expo*c/(
unif*beta+halfpi)))/Math.PI;
}
var z=-Math.Tan(halfpi*alpha)*beta;
var ug=unif+Math.Atan(-z)/alpha;
var cpow=Math.Pow(c, -1.0 / alpha);
return Math.Pow(1.0+z*z, 1.0 / (2*alpha))*
(Math.Sin(alpha*ug)*cpow)*
Math.Pow(Math.Cos(unif-alpha*ug)/expo, (1.0-alpha) / alpha);
}
private static double NextDouble(Random rand){
// The default NextDouble implementation in .NET (see
// https://github.com/dotnet/corert/blob/master/src/System.Private.CoreLib/shared/System/Random.cs)
// is very problematic:
// - It generates a random number 0 or greater and less than 2^31-1 in a
// way that very slightly biases 2^31-2.
// - Then it divides that number by 2^31-1.
// - The result is a number that uses roughly only 32 bits of pseudorandomness,
// even though `double` has 53 bits in its significand.
// To alleviate some of these problems, this method generates a random 53-bit
// random number and divides that by 2^53. Although this doesn't fix the bias
// mentioned above (for the default System.Random), this bias may be of
// negligible importance for most purposes not involving security.
long x=rand.Next(0,1<<30);
x<<=23;
x+=rand.Next(0,1<<23);
return (double)x / (double)(1L<<53);
}
此外,我在另一篇文章中阐述了稳定分布的伪代码。