scipy 没有 scipy.stats.fit(),需调用具体分布类的 fit() 方法(如 stats.norm.fit);k-s 检验不能用于同一数据拟合后检验;多分布比较需手动计算 aic/bic;可视化时须注意 bin 选择、pdf 归一化及定义域匹配。

scipy.stats.fit() 不存在,别被名字误导
很多人搜 scipy.stats.fit 想直接拟合分布,但这个函数根本不存在——Scipy 没有统一的 fit() 方法入口。实际要用的是各个分布类自带的 fit() 方法,比如 scipy.stats.norm.fit() 或 scipy.stats.gamma.fit()。误以为有通用接口,容易卡在语法错误上。
关键点在于:必须先**明确假设分布类型**,再调用对应分布的 fit()。Scipy 不做自动分布识别,也不比较 AIC/BIC;它只负责给定分布下的参数估计。
- 常见误操作:
scipy.stats.fit(data, 'gamma')—— 这会报AttributeError - 正确写法:
scipy.stats.gamma.fit(data),返回(a, loc, scale)三元组 - 注意
loc和scale默认参与估计;若想固定位置(如 gamma 要求loc=0),得显式传参:scipy.stats.gamma.fit(data, floc=0)
KS 检验(kstest)不是万能的,尤其对拟合分布要慎用
用 scipy.stats.kstest 检验“数据是否来自某分布”时,如果分布参数是用同一份数据估计出来的(即先 fit 再 kstest),p 值会严重偏高,检验失效。这是经典陷阱:K-S 检验要求分布参数已知,而非从样本估计。
真正可用的方式只有两种:
- 用独立验证集:拟合用训练子集,
kstest用另一份未参与拟合的数据 - 改用
scipy.stats.kstest的args参数传入已知真值参数(非估计值) - 或换用专门处理“估计后检验”的方法,比如
scipy.stats.powerlaw.fit配合scipy.stats.ks_1samp+ 参数 Bootstrap 校正(但 Scipy 不内置此流程,需手动实现)
示例错例:params = scipy.stats.lognorm.fit(data); kstest(data, 'lognorm', args=params) —— 这个 p 值不可信。
多分布批量拟合与比较,得自己搭评估逻辑
Scipy 不提供像 R 的 fitdistrplus 那样的多分布并行拟合+指标汇总功能。你要对比 norm、lognorm、weibull_min 哪个更优,就得手动循环拟合、提取参数、计算 AIC/BIC 或负对数似然。
核心难点在 BIC 计算:Scipy 分布对象没有 .logpdf().sum() 的便捷聚合,得自己算:
import numpy as np from scipy import stats <p>dist = stats.norm params = dist.fit(data) llf = np.sum(dist.logpdf(data, <em>params)) n = len(data) k = len(params) bic = -2 </em> llf + k * np.log(n)</p>
-
logpdf返回每个点的对数密度,必须用np.sum聚合,不能只取均值 - 不同分布自由度
k不同:norm是 2(loc,scale),gamma是 3(a,loc,scale),beta是 4 - 有些分布(如
johnsonsu)参数语义复杂,fit()可能收敛失败,需加try/except和初始值控制
拟合结果可视化时,直方图 bin 数和 PDF 归一化必须匹配
用 plt.hist(data, density=True) 画直方图,再叠 scipy.stats.xxx.pdf(x, *params) 曲线,看似合理,但常因 bin 数太少或太多导致形状失真,掩盖拟合质量问题。
- 推荐用
bins='auto'或bins=int(np.sqrt(len(data)))起手,而非默认 10 - PDF 曲线的 x 范围必须覆盖数据极值,且点数足够(建议至少 200 点):
x = np.linspace(np.min(data), np.max(data), 200) - 特别注意:
scipy.stats.lognorm.pdf的参数顺序是(s, loc, scale),不是(shape, loc, scale);s是 shape 参数,易和gamma.a混淆 - 若数据含负值,别硬套
lognorm或weibull_min——它们定义域为正,拟合会静默失败(返回不合理参数)
最常被跳过的检查:画完图后,用 np.allclose(np.trapz(pdf_curve, x), 1.0, atol=1e-2) 确认 PDF 积分为 1,否则归一化出错,图就失去可比性。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











