Python中未知底层分布时,如何拟合蒙特卡洛模拟得到的直方图?
解决Monte Carlo样本直方图拟合精度低的问题
1. 先确认样本是否真的服从正态分布
大样本下强行拟合正态分布本身就可能不合理,先通过统计方法验证:
- 用拟合优度检验:大样本推荐Kolmogorov-Smirnov检验,代码示例(Python):
import numpy as np from scipy import stats sample = # 你的Monte Carlo样本数组 mu, sigma = np.mean(sample), np.std(sample) stat, p_value = stats.kstest(sample, 'norm', args=(mu, sigma)) # 若p值远小于0.05,说明样本不服从正态分布 - 绘制Q-Q图:直观观察样本分位数与正态分布分位数的匹配度:
如果点明显偏离直线,说明正态假设不成立。import matplotlib.pyplot as plt stats.probplot(sample, plot=plt) plt.show()
2. 尝试适配样本形态的其他分布
如果正态分布不适用,根据直方图形态选择对应分布:
- 若直方图右偏:尝试对数正态分布、伽马分布或威布尔分布
- 若直方图左偏:尝试反转的伽马分布或Beta分布(取值在0-1之间时)
- 若为双峰形态:考虑混合正态分布或多个单峰分布的叠加
用最大似然估计拟合分布参数,以伽马分布为例:
shape, loc, scale = stats.gamma.fit(sample) # 生成拟合的分布曲线 x = np.linspace(min(sample), max(sample), 1000) pdf = stats.gamma.pdf(x, shape, loc, scale)
3. 优化正态拟合的鲁棒性(若坚持用正态分布)
如果业务场景要求必须用正态拟合,可通过以下方法提升精度:
- 用**中位数+绝对偏差(MAD)**替代均值和标准差,降低异常值影响:
median = np.median(sample) mad = np.median(np.abs(sample - median)) * 1.4826 # 转换为与标准差等价的尺度 - 优化直方图分箱:用Freedman-Diaconis准则确定分箱数,避免分箱偏差:
合理的分箱能更准确反映样本分布形态,减少拟合时的视觉误差。iqr = stats.iqr(sample) bin_width = 2 * iqr / (len(sample)**(1/3)) bins = int((np.max(sample) - np.min(sample)) / bin_width)
4. 大样本拟合的评估逻辑
10万样本属于超大样本,视觉上的微小偏差可能不影响统计意义:
- 不要仅依赖视觉匹配,用卡方检验或R²量化拟合效果:
# 计算直方图观测频数 observed, bin_edges = np.histogram(sample, bins=bins) # 计算正态分布的期望频数 expected = len(sample) * np.diff(stats.norm.cdf(bin_edges, mu, sigma)) chi_sq, p_val = stats.chisquare(observed, expected) - 若p值>0.05,说明拟合的正态分布与样本无显著差异。
内容的提问来源于stack exchange,提问作者Firebolt
相关产品推荐
相关产品推荐

