Reputation: 93
I have the code which generates a normal distribution as a pdf, centered at the mean 400, with st
import numpy as np
import matplotlib.pyplot as plt
import scipy.stats
muPrev, sigmaPrev = 400, 40.
a = np.random.normal(muPrev, sigmaPrev, 100000)
count, bins, ignored = plt.hist(a, 1000, density=True)
plt.plot(bins, 1/(sigmaPrev * np.sqrt(2 * np.pi)) *
np.exp( - (bins - muPrev)**2 / (2 * sigmaPrev**2) ),linewidth=3, color='r')
and I can visualise it. But what if I wanted to convert this into a lognormal distribution? So that I now get values of mu and sigma that correspond to this as a log distribution?
Upvotes: 0
Views: 1682
Reputation: 20130
What is posted by @SamMason is not correct. It is somewhat working because your mean and sd are relative large.
Ok, here is what would be correct way to get parameters of the Log-Normal distribution.
You have predefined values of mean (corresponding to your Gaussian mean) and sd (again, your Gaussian sd).
Mean=exp(μ+σ2/2)
Var =(exp(σ2) - 1)(exp(2μ+σ2))
Here μ and σ are log-normal (NOT gaussian) parameter. You have to find them.
UPDATE
Mean2=exp(2μ+σ2)
Var/Mean2 = (exp(σ2) - 1)
So here is your σ. To be more elaborate
Sd2/Mean2 = exp(σ2) - 1
exp(σ2) = 1 + Sd2/Mean2
σ2 = ln(1 + Sd2/Mean2)
From first equation now you could get μ
2μ+σ2 = ln(Mean2)
2μ=ln(Mean2) - σ2 = ln(Mean2) - ln(1 + Sd2/Mean2) = ln((Mean2)/(1 + Sd2/Mean2))
Please, check the math, but this is the way to get PRECISE log-normal μ,σ parameters to match desired Mean and Sd.
@SamMason approximation works, I believe, only if in the expression for
σ2 = ln(1 + Sd2/Mean2)
one have second term much larger than 1. THen you could drop 1 and have log of ratios.
UPDATE II
2μ=ln((Mean2)/(1 + Sd2/Mean2)) = ln(Mean4/(Mean2 + Sd2))
μ=1/2 ln(Mean4/(Mean2 + Sd2))=ln(Mean2/Sqrt(Mean2 + Sd2))
Upvotes: 2
Reputation: 16213
To give a more complete answer, here's some code that draws a figure with two plots: one shows your existing Gaussian draws and another for log-normal draws. I keep the first and second moments the same (i.e. mean and variance) by setting the log-normal mu=log(mu)
and sigma=sd/mu
.
import numpy as np
import scipy.stats as sps
import matplotlib.pyplot as plt
mu, sd = 400, 40
n = 100_000
# draw samples from distributions
a = np.random.normal(mu, sd, n)
b = np.random.lognormal(np.log(mu), sd / mu, n)
# use Scipy for analytical PDFs
d1 = sps.norm(mu, sd)
# warning: scipy parameterises its distributions very strangely
d2 = sps.lognorm(sd / mu, scale=mu)
# bins to use for histogram and x for PDFs
lo, hi = np.min([a, b]), np.max([a, b])
dx = (hi - lo) * 0.06
bins = np.linspace(lo, hi, 101)
x = np.linspace(lo - dx, hi + dx, 501)
# draw figure
fig, [ax1, ax2] = plt.subplots(nrows=2, sharex=True, sharey=True, figsize=(8, 5))
ax1.set_title("Normal draws")
ax1.set_xlim(lo - dx, hi + dx)
ax1.hist(a, bins, density=True, alpha=0.5)
ax1.plot(x, d1.pdf(x))
ax1.plot(x, d2.pdf(x), '--')
ax2.set_title("Log-Normal draws")
ax2.hist(b, bins, density=True, alpha=0.5, label="Binned density")
ax2.plot(x, d1.pdf(x), '--', label="Normal PDF")
ax2.plot(x, d2.pdf(x), label="Log-Normal PDF")
ax2.legend()
fig.supylabel("Density")
which produces the following output:
Because the distributions are so close here, I've included dashed lines to show the other distribution for easier comparison. Note that the log-normal distribution will always be slightly right-skewed, more so as the variance increases.
Upvotes: 0
Reputation: 172
You could directly generate samples for a lognormal distribution with https://numpy.org/doc/stable/reference/random/generated/numpy.random.lognormal.html, alternatively:
log_norm = np.exp(a)
Note that if you want to generate the lognormal directly you need to calculate the appropriate mean and variance https://en.wikipedia.org/wiki/Log-normal_distribution
Upvotes: 0