如何为已有直方图实现Weibull拟合?Scipy使用问题求助
解决Weibull拟合曲线与直方图不匹配的问题
看起来你遇到的核心问题是直方图的频数尺度和Weibull概率密度函数(PDF)的概率尺度不匹配,再加上拟合参数的小细节可以优化,下面一步步帮你解决:
1. 匹配直方图与PDF的尺度
直方图展示的是每个区间的样本频数(即该区间内有多少个数据点),而stats.weibull_min.pdf()返回的是概率密度值(所有区间的密度积分总和为1)。要让两者在图上匹配,必须把PDF的值乘以两个关键系数:
- 样本总数(
len(X)):把概率转换为频数基数 - 直方图的组距(这里你设置的是25,因为
bins=np.arange(0,1500,25)):把密度值拉伸到对应区间的宽度
2. 优化拟合参数
你的数据是x>0的时间间隔,Weibull分布的位置参数loc理论上应该为0(时间间隔不可能为负),所以在fit()时指定floc=0,可以强制固定位置参数,避免拟合出不合理的loc值,让形状参数shape和尺度参数scale的估计更准确。
完整修改后的代码
把所有调整整合到你的原代码中:
import pandas as pd import matplotlib.pyplot as plt import numpy as np import scipy.stats as stats # 读取数据 hist = pd.read_excel('Histogram/Histogram.xlsx') X = hist['DeltaT_-250_2017'] X = X[(X > 0)] # 绘制直方图,同时获取频数和区间信息 bin_width = 25 bins = np.arange(0, 1500, bin_width) plt.figure(figsize=(15,4)) n, bins, patches = plt.hist(X, bins=bins, color='#0504aa', edgecolor='red', rwidth=0.8) plt.ylabel('Number of EL') plt.xlabel('Delta T (years CE) between EL') plt.xlim(0, 401) plt.xticks(np.arange(0, 401, 25)) plt.yticks(np.arange(0, max(n)+1, 1)) # 自动匹配y轴的频数范围 # Weibull 拟合与适配尺度的曲线绘制 shape, loc, scale = stats.weibull_min.fit(X, floc=0) x = np.linspace(0, 401, 100) # 和直方图的x轴范围保持一致 # 计算匹配频数尺度后的PDF值 pdf_values = stats.weibull_min.pdf(x, shape, loc=loc, scale=scale) * len(X) * bin_width plt.plot(x, pdf_values, 'r-', lw=2, alpha=0.8, label=f'Weibull Fit\nshape={shape:.2f}, scale={scale:.2f}') plt.legend() plt.show()
为什么原来的曲线不对?
你之前直接绘制的是原始概率密度值,其数值范围远小于直方图的频数(比如如果你的样本数是20,组距25,那么PDF需要乘以20*25才能和直方图的高度匹配),所以看起来会是一条和直方图完全不搭的扁平线条或者错位图形。
内容的提问来源于stack exchange,提问作者Mat B
相关产品推荐
相关产品推荐

