Вопрос

Wenping (Wendy) Zhang points out that the SAS RAND function "basically gives "standard" distribution".

The author describes an interesting SAS %rndnmb macro to generate data from “non-standard” distributions. Unfortunately the code in unavailable. So, I dared to do it by myself.

If I understand correctly the Wikipedia says that y is from the log-normal distribution if
y = exp^(mu + sigma * Z).
The following formulas connect the mean and variance of the non-logarithmized sample values:
mu = ln((mean^2)/(sqrt(variance + mean^2))
and
sigma = sqrt(ln(1 + (variance)/(mean^2))).

If that correct, my y will be drawn from log-normal distribution when
Z is from standard normal distribution Z with mu' = 0, sigma' = 1.

Finally, is it correct that y is from lognormal distribution with mean and variance if
y = exp^(ln((mean^2)/(sqrt(variance + mean^2)) + sqrt(ln(1 + (variance)/(mean^2))) * Z) ?

My SAS code is:
/*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;

References:
RAND function by Rick Wicklin: 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/

Это было полезно?

Решение

What you need is the inverse cumulative distribution function. This is the function that is the inverse of the normalized integral of the distribution over the entire domain. So at 0% is your most negative possible value and 100% is your most positive. Practically though you would calmp to something like 0.01% and 99.99% or something like that as otherwise you'll end up at infinite for a lot of distributions.

Then from there you only need to random a number in a range (0,1) and plug that into the function. Remember to clamp it!

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

so

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

should give you the requested distribution. inverf is the inverse of the erf function. It is a common function but not in math.h typically.

Did a SIMD based random number generator that needed to do distributions. This worked fine, the above will work assuming I didn't flub up something while typing.

As requested how to clamp:

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

Другие советы

If you want Z to be drawn from the standard normal distribution, shouldn't you obtain it by calling RAND('NORMAL') rather than RAND('UNIFORM')?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top