拟合#
- scipy.stats.fit(dist, data, bounds=None, *, guess=None, method='mle', optimizer=<function differential_evolution>)[源代码]#
将离散或连续分布拟合到数据
给定一个分布、数据和分布参数的边界,返回参数的最大似然估计。
- 参数:
- dist
scipy.stats.rv_continuous
或scipy.stats.rv_discrete
表示要拟合到数据的分布的对象。
- data一维类数组
要将分布拟合到的数据。如果数据包含任何
np.nan
、np.inf
或 -np.inf
,则拟合方法将引发ValueError
。- bounds字典或元组序列,可选
如果是一个字典,则每个键是分布的参数名称,并且对应的值是一个包含该参数的下限和上限的元组。如果分布仅对该参数的有限值范围定义,则不需要该参数的条目;例如,某些分布的参数必须位于区间 [0, 1] 内。参数 location (
loc
) 和 scale (scale
) 的边界是可选的;默认情况下,它们分别固定为 0 和 1。如果是一个序列,则元素 i 是一个包含分布的第 i 个参数的下限和上限的元组。在这种情况下,必须提供所有分布形状参数的边界。可选地,位置和尺度的边界可以跟随分布形状参数。
如果要保持形状固定(例如,如果已知),则下限和上限可以相等。如果用户提供的下限或上限超出定义分布的域的边界,则分布域的边界将替换用户提供的值。类似地,必须是整数的参数将被约束为用户提供的边界内的整数值。
- guess字典或类数组,可选
如果是一个字典,则每个键是分布的参数名称,并且对应的值是该参数值的猜测。
如果是一个序列,则元素 i 是分布的第 i 个参数的猜测。在这种情况下,必须提供所有分布形状参数的猜测。
如果未提供 guess,则不会将决策变量的猜测传递给优化器。如果提供了 guess,则任何缺失参数的猜测都将设置为下限和上限的平均值。必须是整数的参数的猜测将被四舍五入为整数值,并且位于用户提供的边界和分布域的交集之外的猜测将被裁剪。
- method{‘mle’, ‘mse’}
使用
method="mle"
(默认值),通过最小化负对数似然函数来计算拟合。对于超出分布支持范围的观测值,将应用较大的有限惩罚(而不是无限负对数似然)。使用method="mse"
,通过最小化负对数乘积间距函数来计算拟合。对于超出支持范围的观测值,应用相同的惩罚。我们遵循 [1] 的方法,该方法针对具有重复观测值的样本进行了推广。- optimizer可调用对象,可选
optimizer 是一个接受以下位置参数的可调用对象。
- fun可调用对象
要优化的目标函数。 fun 接受一个参数
x
,即分布的候选形状参数,并返回给定x
、dist 和提供的 data 的目标函数值。 optimizer 的工作是找到最小化 fun 的决策变量的值。
optimizer 还必须接受以下关键字参数。
- bounds元组序列
决策变量值的边界;每个元素将是一个包含决策变量的下限和上限的元组。
如果提供了 guess,则 optimizer 还必须接受以下关键字参数。
- x0类数组
每个决策变量的猜测。
如果分布有任何必须是整数的形状参数,或者如果分布是离散的并且位置参数未固定,则 optimizer 还必须接受以下关键字参数。
- integrality布尔值类数组
对于每个决策变量,如果决策变量必须约束为整数值,则为 True;如果决策变量是连续的,则为 False。
optimizer 必须返回一个对象,例如
scipy.optimize.OptimizeResult
的实例,该对象在其属性x
中保存决策变量的最优值。如果提供了属性fun
、status
或message
,则它们将包含在fit
返回的结果对象中。
- dist
- 返回:
- result
FitResult
具有以下字段的对象。
- params命名元组
一个包含分布的形状参数、位置和(如果适用)比例的最大似然估计的命名元组。
- success布尔值或 None
优化器是否认为优化已成功终止。
- message字符串或 None
优化器提供的任何状态消息。
该对象具有以下方法
- nllf(params=None, data=None)
默认情况下,给定 data 的拟合 params 处的负对数似然函数。接受一个包含分布的替代形状、位置和比例的元组以及一个替代数据数组。
- plot(ax=None)
将拟合分布的 PDF/PMF 叠加在数据的归一化直方图上。
- result
另请参阅
备注
当用户提供包含最大似然估计的紧密边界时,优化更有可能收敛到最大似然估计。例如,当将二项分布拟合到数据时,每个样本的基础实验次数可能是已知的,在这种情况下,可以固定相应的形状参数
n
。参考文献
[1]Shao, Yongzhao, and Marjorie G. Hahn. “Maximum product of spacings method: a unified formulation with illustration of strong consistency.” Illinois Journal of Mathematics 43.3 (1999): 489-499.
示例
假设我们希望将分布拟合到以下数据。
>>> import numpy as np >>> from scipy import stats >>> rng = np.random.default_rng() >>> dist = stats.nbinom >>> shapes = (5, 0.5) >>> data = dist.rvs(*shapes, size=1000, random_state=rng)
假设我们不知道数据是如何生成的,但我们怀疑它遵循具有参数 n 和 p 的负二项分布。(请参见
scipy.stats.nbinom
。)我们认为参数 n 小于 30,并且我们知道参数 p 必须位于区间 [0, 1] 内。我们将此信息记录在变量 bounds 中,并将此信息传递给fit
。>>> bounds = [(0, 30), (0, 1)] >>> res = stats.fit(dist, data, bounds)
fit
在用户指定的 bounds 内搜索最匹配数据的值(从最大似然估计的意义上来说)。在这种情况下,它找到的形状值与实际生成数据的值相似。>>> res.params FitParams(n=5.0, p=0.5028157644634368, loc=0.0) # may vary
我们可以通过将分布的概率质量函数(形状与数据拟合)叠加在数据的归一化直方图上来可视化结果。
>>> import matplotlib.pyplot as plt # matplotlib must be installed to plot >>> res.plot() >>> plt.show()
请注意,n 的估计值正好是整数;这是因为
nbinom
PMF 的定义域仅包含整数 n,并且nbinom
对象“知道”这一点。nbinom
也知道形状参数 p 必须是 0 到 1 之间的值。在这种情况下 - 当分布关于参数的定义域是有限的时 - 我们不需要为该参数指定边界。>>> bounds = {'n': (0, 30)} # omit parameter p using a `dict` >>> res2 = stats.fit(dist, data, bounds) >>> res2.params FitParams(n=5.0, p=0.5016492009232932, loc=0.0) # may vary
如果我们希望强制分布拟合时 n 固定为 6,我们可以将 n 的上下边界都设置为 6。但请注意,在这种情况下,通常被优化的目标函数的值会更差(更高)。
>>> bounds = {'n': (6, 6)} # fix parameter `n` >>> res3 = stats.fit(dist, data, bounds) >>> res3.params FitParams(n=6.0, p=0.5486556076755706, loc=0.0) # may vary >>> res3.nllf() > res.nllf() True # may vary
请注意,前面示例的数值结果是典型的,但它们可能会有所不同,因为
fit
使用的默认优化器,scipy.optimize.differential_evolution
,是随机的。但是,我们可以自定义优化器使用的设置以确保可重复性 - 或者甚至可以使用完全不同的优化器 - 使用 optimizer 参数。>>> from scipy.optimize import differential_evolution >>> rng = np.random.default_rng() >>> def optimizer(fun, bounds, *, integrality): ... return differential_evolution(fun, bounds, strategy='best2bin', ... rng=rng, integrality=integrality) >>> bounds = [(0, 30), (0, 1)] >>> res4 = stats.fit(dist, data, bounds, optimizer=optimizer) >>> res4.params FitParams(n=5.0, p=0.5015183149259951, loc=0.0)