Generate random numbers from lognormal distribution in python

Bobesh

I need to generate pseudo-random numbers from a lognormal distribution in Python. The problem is that I am starting from the mode and standard deviation of the lognormal distribution. I don't have the mean or median of the lognormal distribution, nor any of the parameters of the underlying normal distribution.

numpy.random.lognormal takes the mean and standard deviation of the underlying normal distribution. I tried to calculate these from the parameters I have, but wound up with a quartic function. It has a solution, but I hope that there is a more straightforward way to do this.

scipy.stats.lognorm takes parameters that I don't understand. I am not a native English speaker and the documentation doesn't make sense.

Can you help me, please?

Warren Weckesser

You have the mode and the standard deviation of the log-normal distribution. To use the rvs() method of scipy's lognorm, you have to parameterize the distribution in terms of the shape parameter s, which is the standard deviation sigma of the underlying normal distribution, and the scale, which is exp(mu), where mu is the mean of the underlying distribution.

You pointed out that making this reparameterization requires solving a quartic polynomial. For that, we can use the numpy.poly1d class. Instances of that class have a roots attribute.

A little algebra shows that exp(sigma**2) is the unique positive real root of the polynomial

x**4 - x**3 - (stddev/mode)**2 = 0

where stddev and mode are the given standard deviation and mode of the log-normal distribution, and for that solution, the scale (i.e. exp(mu)) is

scale = mode*x

Here's a function that converts the mode and standard deviation to the shape and scale:

def lognorm_params(mode, stddev):
    """
    Given the mode and std. dev. of the log-normal distribution, this function
    returns the shape and scale parameters for scipy's parameterization of the
    distribution.
    """
    p = np.poly1d([1, -1, 0, 0, -(stddev/mode)**2])
    r = p.roots
    sol = r[(r.imag == 0) & (r.real > 0)].real
    shape = np.sqrt(np.log(sol))
    scale = mode * sol
    return shape, scale

For example,

In [155]: mode = 123

In [156]: stddev = 99

In [157]: sigma, scale = lognorm_params(mode, stddev)

Generate a sample using the computed parameters:

In [158]: from scipy.stats import lognorm

In [159]: sample = lognorm.rvs(sigma, 0, scale, size=1000000)

Here's the standard deviation of the sample:

In [160]: np.std(sample)
Out[160]: 99.12048952171304

And here's some matplotlib code to plot a histogram of the sample, with a vertical line drawn at the mode of the distribution from which the sample was drawn:

In [176]: tmp = plt.hist(sample, normed=True, bins=1000, alpha=0.6, color='c', ec='c')

In [177]: plt.xlim(0, 600)
Out[177]: (0, 600)

In [178]: plt.axvline(mode)
Out[178]: <matplotlib.lines.Line2D at 0x12c5a12e8>

The histogram:

histogram


If you want to generate the sample using numpy.random.lognormal() instead of scipy.stats.lognorm.rvs(), you can do this:

In [200]: sigma, scale = lognorm_params(mode, stddev)

In [201]: mu = np.log(scale)

In [202]: sample = np.random.lognormal(mu, sigma, size=1000000)

In [203]: np.std(sample)
Out[203]: 99.078297384090902

I haven't looked into how robust poly1d's roots algorithm is, so be sure to test for a wide range of possible input values. Alternatively, you can use a solver from scipy to solve the above polynomial for x. You can bound the solution using:

max(sqrt(stddev/mode), 1) <= x <= sqrt(stddev/mode) + 1

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

Random samples from Lognormal distribution

Generate random numbers from a distribution given by a list of numbers in python

Generate random numbers from exponential distribution and model using python

Lognormal Distribution from a dataframe in Python

Generate random numbers from a normal distribution

Generate random numbers with a given distribution

Matlab: generate random numbers from normal distribution with given probability

How to generate n random numbers from negative binomial distribution?

Generate random numbers from empirical cumulative distribution function in MATLAB

generate N random numbers from a skew normal distribution using numpy

A lognormal distribution in python

Generate Random numbers from tuple list in Python

Generate random bytearray from a distribution

Generate random numbers with logarithmic distribution and custom slope

How to generate random numbers with predefined probability distribution?

Generate random numbers with a given (numerical) distribution

Generate random numbers with bivariate gamma distribution in R

Generate random numbers with a numerical distribution in given intervals

Generate numbers from normal distribution

Generate Random Number in Range from Single-Tailed Distribution with Python

How to use numpy.random to generate random numbers from a certain distribution?

How to generate n random numbers from a normal distribution using random-fu (Haskell)?

Plotting random numbers from a given distribution along with their expected value in Python

how to generate random numbers (probabilities) from exponential distribution that sum up to 1

generate random decimal numbers from 0 to 1 with normal distribution using numpy

How to generate random positive floating point numbers with normal distribution from 0 up to a given ceiling?

how to generate random numbers from a shifted to the left chi square distribution in R?

Generate random number from custom distribution

Generate a random number from normal distribution in J