【问题标题】:How to configure a function from `scipy.stats` to work with `scipy.optimize.curve_fit`?如何配置来自`scipy.stats`的函数以使用`scipy.optimize.curve_fit`?
【发布时间】:2018-05-06 06:15:23
【问题描述】:

我正在创建一个统一的概率向量,为区域添加权重,再次转换为概率。我想通过将beta 分布拟合到曲线来平滑曲线。我不能使用stats.beta.fit,因为我没有从这些概率中得出任何结论,只有曲线的支架。

如何配置来自scipy.stats 的函数以与scipy.optimize.curve_fit 一起使用?如果可能的话,我不想将其限制为仅beta 分布。有没有一种通用的方法可以将这些转换为可以最小化以优化参数集的形式?

本质上,我正在寻找最适合特定分布的曲线的参数集(在本例中为beta)。

有什么想法吗?

# Uniform probabilities
n = 10
x = np.linspace(0,1,n)
probs_num = np.ones(n)/n # y-values

# Update the mass around an area
idx_update = 2
probs_num[idx_update] += 0.382

# Convert fo probs
probs_num = probs_num/probs_num.sum()

# Plot
with plt.style.context("ggplot"):
    fig, ax = plt.subplots()
    ax.plot(x,probs_num)
    ax.set_ylabel("Density")
    ax.set_xlabel("$x$")


probs_num

from scipy.optimize import curve_fit
from scipy import stats
popt, pcov = curve_fit(stats.beta, x, probs_num) # NOTE: I know this is the wrong way to use it but I'm leaving it as a placeholder

回应下面的lm回答:

import lmfit
def beta_fcn(x, alpha, beta, loc):
    return stats.beta.pdf(x, alpha, beta, loc)
bmodel = lmfit.Model(beta_fcn)
params = bmodel.make_params(alpha=1, beta=1., loc=0.5)
result = bmodel.fit(probs_num, params, x=x)

# ---------------------------------------------------------------------------
# ValueError                                Traceback (most recent call last)
# <ipython-input-34-61ec32095934> in <module>()
#       4 bmodel = lmfit.Model(beta_fcn)
#       5 params = bmodel.make_params(alpha=1, beta=1., loc=0.5)
# ----> 6 result = bmodel.fit(probs_num, params, x=x)

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/model.py in fit(self, data, params, weights, method, iter_cb, scale_covar, verbose, fit_kws, nan_policy, **kwargs)
#     871                              scale_covar=scale_covar, fcn_kws=kwargs,
#     872                              nan_policy=self.nan_policy, **fit_kws)
# --> 873         output.fit(data=data, weights=weights)
#     874         output.components = self.components
#     875         return output

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/model.py in fit(self, data, params, weights, method, nan_policy, **kwargs)
#    1215         self.userkws.update(kwargs)
#    1216         self.init_fit = self.model.eval(params=self.params, **self.userkws)
# -> 1217         _ret = self.minimize(method=self.method)
#    1218 
#    1219         for attr in dir(_ret):

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/minimizer.py in minimize(self, method, params, **kws)
#    1636                         val.lower().startswith(user_method)):
#    1637                     kwargs['method'] = val
# -> 1638         return function(**kwargs)
#    1639 
#    1640 

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/minimizer.py in leastsq(self, params, **kws)
#    1288         np.seterr(all='ignore')
#    1289 
# -> 1290         lsout = scipy_leastsq(self.__residual, variables, **lskws)
#    1291         _best, _cov, infodict, errmsg, ier = lsout
#    1292         result.aborted = self._abort

# ~/anaconda/envs/python3/lib/python3.6/site-packages/scipy/optimize/minpack.py in leastsq(func, x0, args, Dfun, full_output, col_deriv, ftol, xtol, gtol, maxfev, epsfcn, factor, diag)
#     385             maxfev = 200*(n + 1)
#     386         retval = _minpack._lmdif(func, x0, args, full_output, ftol, xtol,
# --> 387                                  gtol, maxfev, epsfcn, factor, diag)
#     388     else:
#     389         if col_deriv:

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/minimizer.py in __residual(self, fvars, apply_bounds_transformation)
#     489         if not self._abort:
#     490             return _nan_policy(np.asarray(out).ravel(),
# --> 491                                nan_policy=self.nan_policy)
#     492 
#     493     def __jacobian(self, fvars):

# ~/anaconda/envs/python3/lib/python3.6/site-packages/lmfit/minimizer.py in _nan_policy(arr, nan_policy, handle_inf)
#    1846 
#    1847         if contains_nan:
# -> 1848             raise ValueError("The input contains nan values")
#    1849     return arr
#    1850 

# ValueError: The input contains nan values

【问题讨论】:

  • 我在bitbucket.org/zunzuncode/tkinterstatsdistrofit 有一个带有 tkinter GUI 的开源 Python 统计分布拟合器,它允许选择不同的 scipy.stats 连续分布进行拟合,这可能会有一些用处。
  • 你可能想要beta.pdf作为概率分布函数,但可能需要其他方法......你还应该意识到它需要4个参数:abloc , 和 `scale

标签: python optimization scipy distribution curve-fitting


【解决方案1】:

您可能想使用beta.pdf,如下所示:

import numpy as np
from scipy import stats
from scipy.optimize import curve_fit
import matplotlib.pyplot as plt

n = 21
x = np.linspace(0, 1, n)
y = stats.beta.pdf(x, 2.5, 15, 0.3) + np.random.normal(scale=0.1, size=n)

p0 = [2.0, 10.0, 0.5]
popt, pcov = curve_fit(stats.beta.pdf, x, y, p0)
print(popt)

您可能还会发现 lmfit (https://lmfit.github.io/lmfit-py/) 很有用。为此,您必须包装 stats.beta.pdf,但这为您设置参数界限或修复参数提供了更大的灵活性:

from lmfit import Model
def beta_fcn(x, alpha, beta, loc):
    return stats.beta.pdf(x, alpha, beta, loc)

bmodel = Model(beta_fcn)

params = bmodel.make_params(alpha=2, beta=10., loc=0.5)
params['alpha'].min = 1.0

result = bmodel.fit(y, params, x=x)

print(result.fit_report())

with plt.style.context("ggplot"):
    fig, ax = plt.subplots()
    ax.plot(x, y, 'o')
    ax.plot(x, result.best_fit)
    ax.set_ylabel("Density")
    ax.set_xlabel("$x$")
plt.show()

这将打印出来

[[Model]]
    Model(beta_fcn)
[[Fit Statistics]]
    # fitting method   = leastsq
    # function evals   = 75
    # data points      = 21
    # variables        = 3
    chi-square         = 0.06244742
    reduced chi-square = 0.00346930
    Akaike info crit   = -116.177008
    Bayesian info crit = -113.043441
[[Variables]]
    alpha:  2.50445306 +/- 0.06843391 (2.73%) (init = 2)
    beta:   14.9105872 +/- 0.31198655 (2.09%) (init = 10)
    loc:    0.29906057 +/- 0.00190835 (0.64%) (init = 0.5)
[[Correlations]] (unreported correlations are < 0.100)
    C(alpha, beta) =  0.894
    C(alpha, loc)  = -0.834
    C(beta, loc)   = -0.564

(并且,需要明确的是,最佳拟合值和不确定性将与上面的 curve_fit 示例相同)和

【讨论】:

  • 哇,我需要稍微拆开包装。感谢您的替代建议。我的同事在所有事情上都使用 glms,但我从来没有真正理解他何时或为什么使用它们。
  • 为什么投反对票?我认为stats.beta.pdf 回答了实际问题,提供了一个可行的示例,并建议了一个替代方案。
  • @O.rka 我认为重点是:使用stats.beta.pdf。第二点:lmfit 为曲线拟合提供了更高级别的接口。 “glms”是指广义线性模型吗?这与 curve_fit() 使用的非线性最小二乘法曲线拟合非常不同。
  • 另外,我用我的数据尝试了你的代码,但在nans 方面出现错误,尽管没有nan 值。我在问题中添加了详细信息。
  • @O.rka 是的,beta 函数似乎很容易出现 NaNInf.... 我不确定为什么会这样,但你可能不得不玩边界在参数上以防止这种情况。因此,lmfit 建议可以轻松地为每个命名参数单独设置边界。
猜你喜欢
  • 1970-01-01
  • 2021-09-29
  • 1970-01-01
  • 2017-03-30
  • 2018-11-22
  • 1970-01-01
  • 1970-01-01
  • 2018-11-14
  • 1970-01-01
相关资源
最近更新 更多