我在一个项目中将Scipy版本从1.8.1更新到1.9.0,同时将Numpy版本保持在1.24.4。然而,这一更改导致项目中断。下面的代码片段重现了这个问题,其中涉及使用Scipy的beta-二项式分布拟合概率分布。
from collections import Counter
import numpy as np
from scipy import stats
from scipy.optimize import differential_evolution
def func_nll(free_params, *args):
"""Negative log likelihood used in the optimizer to fit the best probability distribution available.
More information on the optimizer used in
https://docs.scipy.org/doc/scipy/reference/generated/scipy.optimize.differential_evolution.html
Arguments:
free_params: probability distribution parameters under tuning. Depending on the probability
distribution to fit, there can be one or more
*args: custom distribution arguments, including the
Returns:
Negative log likelihood value used in the optimizer
"""
dist, x, shift = args
# negative log-likelihood function
negativeLogLikelihood = -dist.logpmf(x, loc=shift, *free_params).sum()
if np.isnan(negativeLogLikelihood): # occurs when x is outside of support
negativeLogLikelihood = np.inf # we don't want that
return negativeLogLikelihood
def fit(x, shift):
bounds = [(0, n+1), (1, 700), (1, 700)]
dist = stats.betabinom
opt_res = differential_evolution(func_nll, bounds, maxiter=100, tol=0.001, seed=45,
args=(dist, x, shift))
return opt_res
x = [28, 67, 69, 69, 71, 69, 55, 65, 68, 67, 67, 68, 69, 60, 40]
n = max(x)
mode_value = Counter(x).most_common(1)[0][1]
n_zero = 4288 # high number of zeroes
is_zero_inflated = (n_zero >= mode_value)
shift_loc = 0
if is_zero_inflated:
shift_loc = 1
b_param = fit(x, shift=shift_loc)
print(b_param)
字符串
使用scipy==1.8.1,上面的代码片段打印出来:
df = fun(x) - f0
fun: 49.59657327021416
message: 'Optimization terminated successfully.'
nfev: 2802
nit: 61
success: True
x: array([70.00205357, 6.28931939, 1.0005225 ])
型
当scipy版本更新到1.9.0时,上面的代码片段打印出来:
df = fun(x) - f0
fun: inf
message: 'Maximum number of iterations has been exceeded.'
nfev: 9129
nit: 100
success: False
x: array([ 45.83055307, 3.17350763, 596.7724981 ])
型
我想知道Scipy 1.9.x中beta二项分布的实现是否有突破性的变化可以解释这个问题。
1条答案
按热度按时间igetnqfo1#
我想知道Scipy 1.9.x中beta二项分布的实现是否有突破性的变化可以解释这个问题。
也许吧。在SciPy 1.8.x中检查以下内容:
字符串
我在最近的版本中得到了NaNs,这是一个错误修复。SciPy的β二项分布仅针对整数
n
定义。如果它之前为非整数n
生成了真实的值,那么它可能是底层库的某种无意(并且在数学上不合理)插值。我相信类似的东西在感兴趣的时间框架中得到了修复。在任何情况下,它都可能是
betabinom
、differential_evolution
甚至NumPy中的更改。(例如1.25到1.26),所以SciPy不能保证像differential_evolution
这样的随机算法在主要版本之间的精确再现性。(也就是说,SciPy也不能保证在修复和增强错误时的精确可重复性。它可以防止重大回归和向后不兼容的API更改,但并不是说像differential_evolution
这样的复杂算法总是会返回完全相同的解决方案,甚至在完全相同的问题空间中成功。)但是
scipy.stats.fit
(1.9.0中新增的)解决了你的问题,它使用differential_evolution
来在数值上最小化负对数似然,就像你一样,但是它只传递整数n
作为参数,并且它使用一个惩罚LLF,如果出现NaN或infs,它是鲁棒的。型