【问题标题】:How to generate random numbers from log-normal distribution with a given mean and SD in SAS?如何在 SAS 中从具有给定均值和 SD 的对数正态分布生成随机数?
【发布时间】:2014-07-01 07:32:20
【问题描述】:

张文平(Wendy)张points out SAS RAND function “基本上给出了“标准”分布”。

作者描述了一个有趣的 SAS %rndnmb 宏来从“非标准”分布中生成数据。不幸的是,代码不可用。所以,我敢于自己动手。

如果我正确理解*says y 来自对数正态分布 if
y = exp^(mu + sigma * Z) .
以下公式连接非对数样本值的meanvariance
mu = ln((mean^2)/(sqrt(variance) + 意思是^2))

sigma = sqrt(ln(1 + (variance)/(mean^2))).

如果正确,我的 y 将在
时从对数正态分布中得出 Z 来自标准正态分布 Z,其中 mu' = 0,sigma' = 1。

最后,如果
y = exp^,y 来自 meanvariance 的对数正态分布是否正确(ln((mean^2)/(sqrt(variance + mean^2)) + sqrt(ln(1 + (variance)/(mean^2))) * Z) ?

我的 SAS 代码是:
/*I use StdDev^2 notation instead of variance here. */
DATA nonStLogNorm;
nonStLN = exp(1)**(log((mean**2)/(sqrt(StdDev^2 + mean**2)) + sqrt(log(1 + (StdDev^2)/(mean**2))) * rand('UNIFORM'));
RUN;

参考:
Rick Wicklin 的RAND 函数: http://blogs.sas.com/content/iml/2013/07/10/stop-using-ranuni/ http://blogs.sas.com/content/iml/2011/08/24/how-to-generate-random-numbers-in-sas/

【问题讨论】:

  • 问题是我得到了一个数据集(1000 个变量,值在 79.5200 和 79.7120 之间),平均值(79.6137057)接近 mean(81.2243980),但 SD(15.6962440)非常不同(低得多)来自StdDev (0.05536378)。哪里错了?

标签: function macros sas distribution random-sample


【解决方案1】:

你需要的是逆累积分布函数。这是整个域上分布的归一化积分的反函数。所以 0% 是你最消极的可能值,100% 是你最积极的。实际上,尽管您会平静到 0.01% 和 99.99% 或类似的值,否则您最终会在很多分布中处于无限状态。

然后,您只需在 (0,1) 范围内随机取一个数字并将其插入函数。记得夹住!

double CDF = 0.5 + 0.5*erf((ln(x) - center)/(sqrt(2)*sigma))

所以

double x = exp(inverf((CDF - 0.5)*2.0)*sqrt(2)*sigma + center);

应该给你请求的分布。 inverf 是 erf 函数的逆函数。这是一个常用函数,但通常不在 math.h 中。

做了一个基于 SIMD 的随机数生成器,需要进行分配。这很好用,假设我在打字时没有弄错什么东西的话,上面的方法就可以了。

按要求如何夹紧:

   //This is how I do it with my Random class where the first argument
   //is the min value and the second is the max 
   double CDF = Random::Range(0.0001,0.9999); //Depends on what you are using to random

   //How you get there from Random Ints
   unsigned int RandomNumber = rand();
    //Conver number to range [0,1]
   double CDF = (double)RandomNumber/(double)RAND_MAX; 
   //now clamp it to a min, max of your choosing
   CDF = CDF*(max - min) + min; 

【讨论】:

  • 谢谢,但是我到底应该怎么夹住呢?请问可以放代码吗? 'exp' 你的意思是'CONSTANT('E')**'?
  • 好了,编辑了如何限制值。请记住,随机数生成器的质量会显着影响分布的质量。我不熟悉 SAS,所以我给了你一些等效的 C 代码。但是是的,exp() 函数是某种幂的常数 'e'。在您的环境中可能有一种更简单的方法可以做到这一点,但在幕后这就是正在做的事情。
  • Nope 上面的评论说明了一种从任何随机数生成器中执行此操作的方法。甚至不确定 SAS 是什么。所以我给了他 C 等价物和数学,让他用给定的编程语言创建自己的。只是希望它可以帮助他弄清楚并在您上面的评论中提及这一点。
  • 我没有看到完整的评论。我提交了代码 (CONSTANT('E')**(inverf(((0.5+0.5*erf((log(Min+FLOOR((1+Max-Min)*RAND('LOGNORMAL'))-81.2243980)))/ (sqrt(2)*15.6962440)))- 0.5)*2.0)*sqrt(2)*15.6962440 + 81.2243980));) 但不幸的是 SAS 不知道 inverf()...
  • 您能否解释一下在 CDF 和 X 的情况下“double”是什么意思?据我了解 x = exp(inverf((CDF - 0.5)*2.0)*sqrt(2)*sigma + center),其中 CDF=(0.5 + 0.5*erf((ln(x) - center)/(sqrt( 2)*西格玛)))。对吗?
【解决方案2】:

如果你想从标准正态分布中抽取Z,你不应该通过调用RAND('NORMAL')而不是RAND('UNIFORM')来获得它吗?

【讨论】:

  • 什么是“它”? RAND('UNIFORM') 是否返回钟形直方图?
  • 我的意思是下面的代码(在将 RAND ('UNIFORM) 更改为 RAND('NORMAL') 之后)给了我钟形分布:DATA gfgrgdgd;做 nefff = 1 到 1000; nonStLN = CONSTANT('E')**LOG((81.22439802)/(sqrt(15.69624402+81.22439802)) +sqrt(LOG(1+(15.6962440) 2)/(81.2243980**2)))*RAND('NORMAL')));输出;结束;运行; proc单变量数据= gfgrgdgd;直方图非StLN;运行;
  • sqrt(LOG(1+(15.69624402)/(81.22439802))) 约为 0.1915,从带参数的对数正态图中可以看出sigma=0.25(在*页面上),生成的分布看起来是钟形的。当然,它实际上是偏斜的,但偏斜很难用肉眼看到(与 sigma=1 的偏斜不同,后者非常明显)。但是,如果您仍然得到nonStLN 的微小标准偏差,我会感到困惑。
  • 现在我的问题是 inerf() - SAS 不知道。据说 quantile() 是 user2927848 在他的回答中提到的“CDF 函数的倒数”。