生成对数正态分布随机数为何无法得到预期参数?
对数正态分布随机数生成函数的参数错误修正
问题描述
尝试自行实现生成对数正态分布随机数的函数(用于无现成函数的环境),采用Box-Muller变换生成正态分布随机数后取指数,但生成值的均值和标准差不符合预期,仅分布形状大致正确。原代码如下:
import matplotlib.pyplot as plt import numpy as np rng = np.random.default_rng() def f(): mean = 100 sigma = 50 u = np.log((mean * mean) / np.sqrt(mean * mean + sigma * sigma)) d = np.log(1 + (sigma * sigma) / (mean * mean)) u1 = 0 while u1 <= 0.0000001: u1 = rng.random() u2 = rng.random() mag = d * np.sqrt(-2 * np.log(u1)) z0 = mag * np.cos(2 * np.pi * u2) + u z1 = mag * np.sin(2 * np.pi * u2) + u return (np.exp(z0), np.exp(z1)) iteration = 100000 data = [] for i in range(0, iteration): x = f() data.append(x[0]) data.append(x[1]) fig, ax = plt.subplots() ax.hist(data, bins=100) print('mean: ' + str(np.mean(data))) print('median: ' + str(np.median(data))) print('stdev: ' + str(np.std(data)))
问题根源
核心错误出在正态分布标准差的计算上:
- 对数正态分布的期望
μ_X、标准差σ_X,对应取对数后的正态分布的均值μ_Z和标准差σ_Z的转换公式中,σ_Z是sqrt(ln(1 + (σ_X²/μ_X²))),你遗漏了外层的平方根,直接用ln(1 + (σ_X²/μ_X²))作为标准差,导致生成的正态分布离散程度被放大,最终对数正态分布的方差严重偏离预期。
修正后的代码
import matplotlib.pyplot as plt import numpy as np rng = np.random.default_rng() def f(): mean = 100 # 目标对数正态分布的均值 sigma = 50 # 目标对数正态分布的标准差 # 转换为对应正态分布的均值和标准差 mu_z = np.log((mean ** 2) / np.sqrt(mean ** 2 + sigma ** 2)) sigma_z = np.sqrt(np.log(1 + (sigma ** 2) / (mean ** 2))) # 补上缺失的平方根 u1 = 0 while u1 <= 1e-7: u1 = rng.random() u2 = rng.random() mag = sigma_z * np.sqrt(-2 * np.log(u1)) z0 = mag * np.cos(2 * np.pi * u2) + mu_z z1 = mag * np.sin(2 * np.pi * u2) + mu_z return (np.exp(z0), np.exp(z1)) iteration = 100000 data = [] for i in range(iteration): x = f() data.append(x[0]) data.append(x[1]) fig, ax = plt.subplots() ax.hist(data, bins=100) print('mean: ' + str(np.mean(data))) print('median: ' + str(np.median(data))) print('stdev: ' + str(np.std(data)))
验证结果
修正后运行代码,生成数据的均值会接近100,标准差接近50:
- 对数正态分布的中位数理论值为
exp(mu_z) = 100²/sqrt(100²+50²) ≈ 89.44,输出的中位数会和这个值一致,符合理论预期。
内容的提问来源于stack exchange,提问作者luiges90
相关产品推荐
相关产品推荐

