在 SciPy 中拟合分布时如何检查收敛性
How to check the convergence when fitting a distribution in SciPy
在 SciPy 中拟合分布时有没有办法检查收敛性?
我的目标是将 SciPy 分布(即 Johnson S_U 分布)作为自动数据监控系统的一部分与数十个数据集相匹配。大多数情况下它工作正常,但一些数据集异常并且明显不遵循 Johnson S_U 分布。适合这些数据集 无声地 ,即没有任何 warning/error/whatever!相反,如果我切换到 R 并尝试在那里拟合,我永远不会收敛,这是正确的 - 无论拟合设置如何,R 算法都拒绝声明收敛。
数据:
两个数据集是available in Dropbox:
data-converging-fit.csv
... 一个标准数据,其中拟合很好地收敛(你可能认为这是一个丑陋的、倾斜的、重质的斑点,但约翰逊 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)
我仍然没有收到拟合未能收敛的警告。
通过研究 Whosebug 上的类似问题,我知道了对我的数据进行分类然后使用 curve_fit
的建议。尽管它具有实用性,但我认为该解决方案是不正确的,因为这不是我们拟合分布的方式:分箱是任意的(分箱的数量)并且它会影响最终的拟合。一个更现实的选择可能是 scipy.optimize.minimize
和回调来了解收敛的进展;我仍然不确定它最终会告诉我算法是否收敛。
我怀疑正确的方法是对拟合参数进行统计检验。然后,您将能够设置显着性水平和 accept/reject 数据服从此分布的假设。
johnsonu.fit
方法来自scipy.stats.rv_continuous.fit
。不幸的是,documentation 似乎无法从该方法中获得有关拟合的更多信息。
但是,查看 source code, it appears the actual optimization is done with fmin
,它确实 return 更具描述性的参数。您可以借用源代码并编写自己的 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])
在 SciPy 中拟合分布时有没有办法检查收敛性?
我的目标是将 SciPy 分布(即 Johnson S_U 分布)作为自动数据监控系统的一部分与数十个数据集相匹配。大多数情况下它工作正常,但一些数据集异常并且明显不遵循 Johnson S_U 分布。适合这些数据集 无声地 ,即没有任何 warning/error/whatever!相反,如果我切换到 R 并尝试在那里拟合,我永远不会收敛,这是正确的 - 无论拟合设置如何,R 算法都拒绝声明收敛。
数据: 两个数据集是available in Dropbox:
data-converging-fit.csv
... 一个标准数据,其中拟合很好地收敛(你可能认为这是一个丑陋的、倾斜的、重质的斑点,但约翰逊 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)
我仍然没有收到拟合未能收敛的警告。
通过研究 Whosebug 上的类似问题,我知道了对我的数据进行分类然后使用 curve_fit
的建议。尽管它具有实用性,但我认为该解决方案是不正确的,因为这不是我们拟合分布的方式:分箱是任意的(分箱的数量)并且它会影响最终的拟合。一个更现实的选择可能是 scipy.optimize.minimize
和回调来了解收敛的进展;我仍然不确定它最终会告诉我算法是否收敛。
我怀疑正确的方法是对拟合参数进行统计检验。然后,您将能够设置显着性水平和 accept/reject 数据服从此分布的假设。
johnsonu.fit
方法来自scipy.stats.rv_continuous.fit
。不幸的是,documentation 似乎无法从该方法中获得有关拟合的更多信息。
但是,查看 source code, it appears the actual optimization is done with fmin
,它确实 return 更具描述性的参数。您可以借用源代码并编写自己的 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])