Scipy更新后如何获取对数正态分布的众数?
如何在Scipy #21050更新后获取对数正态分布的众数?
Scipy.stats库原本提供了分布的均值、中位数求解函数,但没有直接的众数求解接口,这也是类似Stack Overflow问题的常见场景。在Scipy的#21050更新后,部分连续分布(包括对数正态分布)新增了mode()方法,同时你也可以通过对数正态分布的理论公式直接计算众数,这比数值求解PDF最大值的方式更精准。
方法一:使用Scipy更新后的mode()方法
在Scipy 1.10.0及以后版本中,scipy.stats.lognorm对象新增了mode()方法,调用后可直接返回分布的众数:
import numpy as np import scipy.stats as stats # 定义对数正态分布参数(s对应sigma,scale对应exp(mu)) sigma = 1 mu = 0 lognorm_dist = stats.lognorm(sigma, scale=np.exp(mu)) # 直接调用mode()方法获取众数 dist_mode = lognorm_dist.mode()[0] print(f"Scipy mode()方法获取的众数: {dist_mode}")
方法二:通过理论公式计算
对数正态分布的众数有明确的理论公式:若底层正态分布的均值为mu、标准差为sigma,则对数正态分布的众数为exp(mu - sigma²)。如果是通过fit()方法拟合数据得到的参数,只需提取对应参数代入公式即可:
import numpy as np import scipy.stats as stats # 模拟样本数据并拟合对数正态分布参数 data = stats.lognorm.rvs(s=1, scale=np.exp(0), size=1000) s_fit, loc_fit, scale_fit = stats.lognorm.fit(data) # 从拟合参数推导mu(scale = exp(mu)) mu_fit = np.log(scale_fit) sigma_fit = s_fit # 计算理论众数 theoretical_mode = np.exp(mu_fit - sigma_fit**2) print(f"理论公式计算的众数: {theoretical_mode}")
原数值求解方案的对比
你提供的数值求解方式是通过寻找PDF最大值对应的x值,这种方法依赖于x的采样密度,精度会受限于采样区间和点数:
import numpy as np import scipy.stats as stats import matplotlib.pyplot as plt mu, sigma = 0, 1 lognorm_dist = stats.lognorm(sigma, scale=np.exp(mu)) x = np.linspace(0, 10, 1_000) y = lognorm_dist.pdf(x) mode = x[np.argmax(y)] print(f"数值求解的众数: {mode}") print(f"理论众数: {np.exp(mu - sigma**2)}") # 可视化对比 plt.plot(x, y, label='对数正态分布PDF') plt.axvline(mode, color='red', linestyle='--', label=f'数值众数: {mode:.4f}') plt.axvline(np.exp(mu - sigma**2), color='green', linestyle='--', label=f'理论众数: {np.exp(mu - sigma**2):.4f}') plt.legend() plt.show()
三种方式对比下来,mode()方法和理论公式计算的结果一致且精度最高,数值求解的结果会因采样设置略有偏差。
内容的提问来源于stack exchange,提问作者Ahmed Thahir
相关产品推荐
相关产品推荐

