如何在C#中生成具有稳定分布的随机数? Random类具有均匀分布。许多其他代码 网络显示正常分布。但我们需要稳定的分配 意思是无限的方差,a.k.a胖尾分布。
原因是产生实际的股票价格。在真实中 世界,价格的巨大变化远远超过 正态分布。
有人知道转换Random类输出的C#代码 进入稳定的分布?
编辑:嗯。精确分布不如确保它会随机产生至少20西格玛的巨大西格玛。我们希望在真正的胖尾分布中测试弹性的交易策略,这正是股票市场价格的行为。我刚刚读到有关ZipFian和Cauchy的评论。因为我必须选择,让我们选择柯西分布,但我也会尝试使用ZipFian进行比较。
答案 0 :(得分:6)
一般来说,方法是:
选择稳定的胖尾发行版。比如,Cauchy分布。
查找所选分布的分位数函数。
对于Cauchy分布,那将是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
答案 1 :(得分:1)
如果您对使用Zipfian分布感兴趣(通常在对来自科学或社交领域的过程进行建模时使用),您可以采取以下措施:
示例代码:
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;
当然,您可以通过从映射并从该域返回值的过程中分解出实现分发域的逻辑来概括整个过程。
答案 2 :(得分:0)
在我的统计学家妻子的礼貌下,詹姆斯·温特的斯普林格卷在这个主题上Random Number Generation and Monte Carlo Methods。它讨论了第105页的稳定族:
稳定的发行家族是一个灵活的一系列通常是重尾的发行版。该族包括在一个参数的一个极值处的正态分布和在另一个极值处的Cauchy。 Chambers,Mallows和Stuck(1976)给出了一种产生偏离稳定分布的方法。 (注意辅助函数D2中常量中的一些错误,用于评估(e x -1)/ x。)它们的方法用于IMSL库。对于对称稳定分布,Devroye(1986)指出,通过利用对称稳定与Fejer-de la Vallee Poissin分布的关系,可以开发出更快的方法。 Buckle(1995)展示了如何根据数据模拟稳定分布的参数。
生成与通用稳定分布的偏差很难。如果你需要这样做,那么我会推荐一个像IMSL这样的库。我不建议你自己尝试一下。
但是,如果您正在寻找稳定家族中的特定分布,例如Cauchy,那么你可以使用Eric描述的方法,称为probability integral transform。只要您能够以封闭形式写下分布函数的反函数,就可以使用这种方法。
答案 3 :(得分:0)
在给定形状参数alpha
和beta
的情况下,以下C#代码会在稳定分布后生成随机数。我将它发布到Creative Commons Zero下的公共领域。
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);
}
另外,我在a separate article中为稳定分布设定了伪代码。