在 SciPy 中拟合分布时如何检查收敛性

Posted

技术标签:

【中文标题】在 SciPy 中拟合分布时如何检查收敛性【英文标题】:How to check the convergence when fitting a distribution in SciPy 【发布时间】:2021-10-16 14:43:47 【问题描述】:

在 SciPy 中拟合分布时有没有办法检查收敛性?

我的目标是将 SciPy 发行版(即 Johnson S_U 发行版)拟合到数十个数据集,作为自动化数据监控系统的一部分。大多数情况下它工作正常,但有一些数据集是异常的,并且显然不遵循 Johnson S_U 分布。适合这些数据集无声地发散,即没有任何警告/错误/无论如何!相反,如果我切换到 R 并尝试在那里拟合,我永远不会得到收敛,这是正确的 - 无论拟合设置如何,R 算法都拒绝声明收敛。

数据: 两个数据集是available in Dropbox:

data-converging-fit.csv ... 一个标准数据,适合很好地收敛(你可能认为这是一个丑陋的、倾斜的、重中心质量的 blob,但 Johnson S_U 足够灵活,可以适应这样的野兽! ):

data-diverging-fit.csv ... 一个异常数据,其中拟合发散:

适合分布的代码:

import pandas as pd
from scipy import stats

distribution_name = 'johnsonsu'
dist = getattr(stats, distribution_name)

convdata = pd.read_csv('data-converging-fit.csv', index_col= 'timestamp')
divdata  = pd.read_csv('data-diverging-fit.csv', index_col= 'timestamp')

在好的数据上,拟合的参数有共同的数量级:

a, b, loc, scale = dist.fit(convdata['target'])
a, b, loc, scale

[out]: (0.3154946859186918, 
 2.9938226613743932,
 0.002176043693009398,
 0.045430055488776266)

在异常数据上,拟合参数不合理:

a, b, loc, scale = dist.fit(divdata['target'])
a, b, loc, scale

[out]: (-3424954.6481554992, 
7272004.43156841, 
-71078.33596490842, 
145478.1300979394)

我仍然没有收到任何关于拟合未能收敛的警告。

通过在 *** 上研究类似问题,我知道将我的数据分箱然后使用 curve_fit 的建议。尽管它具有实用性,但我认为该解决方案并不正确,因为这不是我们拟合分布的方式:分箱是任意的(分箱的数量),它会影响最终的拟合。一个更现实的选择可能是scipy.optimize.minimize 和回调以了解收敛的进度;我仍然不确定它最终会告诉我算法是否收敛。

【问题讨论】:

【参考方案1】:

johnsonu.fit 方法来自scipy.stats.rv_continuous.fit。不幸的是,从documentation 看来,似乎无法从这种方法中获得更多关于拟合的信息。

但是,查看source code,似乎实际优化是使用fmin 完成的,它确实返回了更多描述性参数。您可以从源代码中借用并编写自己的 fit 实现,以检查 fmin 输出参数是否收敛:

import numpy as np
import pandas as pd
from scipy import optimize, stats

distribution_name = 'johnsonsu'
dist = getattr(stats, distribution_name)

convdata = pd.read_csv('data-converging-fit.csv', index_col= 'timestamp')
divdata  = pd.read_csv('data-diverging-fit.csv', index_col= 'timestamp')

def custom_fit(dist, data, method="mle"):
    data = np.asarray(data)
    start = dist._fitstart(data)
    args = [start[0:-2], (start[-2], start[-1])]
    x0, func, restore, args = dist._reduce_func(args, , data=data)
    vals = optimize.fmin(func, x0, args=(np.ravel(data),))
    return vals
custom_fit(dist, convdata['target'])

[out]: Optimization terminated successfully.
         Current function value: -23423.995945
         Iterations: 162
         Function evaluations: 274
array([3.15494686e-01, 2.99382266e+00, 2.17604369e-03, 4.54300555e-02])
custom_fit(dist, divdata['target'])

[out]: Warning: Maximum number of function evaluations has been exceeded.
array([-12835849.95223926,  27253596.647191  ,   -266388.68675908,
          545225.46661612])

【讨论】:

谢谢@turnerm,这个确认(“你需要自己写fit() mthod”)正是我所追求的!我也很欣赏代码。【参考方案2】:

我怀疑正确的方法是对拟合参数进行统计测试。然后,您将能够设置显着性水平并接受/拒绝数据遵循此分布的假设。

【讨论】:

感谢您的建议,@ev-br。最初,我遵循了您建议的方法;它仍然没有揭示分歧问题。而且我不愿意相信在 SciPy 中没有办法找出适合性不同...

以上是关于在 SciPy 中拟合分布时如何检查收敛性的主要内容,如果未能解决你的问题,请参考以下文章

尝试 MLE 拟合 Weibull 分布时 scipy.optimize.minimize 中的 RuntimeWarning

使用 scipy.stats 将 Weibull 分布拟合到数据是不是表现不佳?

使用 Scipy 拟合 Weibull 分布

scipy-optimize-minimize 最小化缺乏收敛性

拟合分布、拟合优度、p 值。是不是可以使用 Scipy (Python) 做到这一点?

拟合分布、拟合优度、p 值。是不是可以使用 Scipy (Python) 做到这一点?