質問

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