scipy.optimize.minimize 选择不受限制的参数

scipy.optimize.minimize choosing parameters that defy constraints

我正在 运行 scipy.optimize.minimize 尝试最大化 Gompertz 分布上左截断数据的可能性。由于数据在 1 处被左截断,我得到这种可能性:

# for a single point x_i, the left-truncated log-likelihood is:
#   ln(tau) + tau*(ln(theta) - ln(x_i)) - (theta / x_i) ** tau - ln(x_i) - ln(1 - exp(-(theta / d) ** tau))
def to_minimize(args, data, d=1):
  theta, tau = args
  if tau <= 0 or theta <= 0 or theta / d < 0 or np.exp(-(theta / d) ** tau) >= 1:
    print('ERROR')
  term1 = len(data) * (np.log(tau) + tau * np.log(theta) - np.log(1 - np.exp(-(theta / d) ** tau)))
  term2 = 0
  for x in data:
    term2 += (-(tau + 1) * np.log(x)) - (theta / x) ** tau
  return term1 + term2

if 语句为真的所有情况下,这将失败。换句话说,tautheta 必须严格为正,并且 theta ** tau 必须与 0 足够远,这样 np.exp(-theta ** tau) 就“足够远” " 来自 1,否则对数将不确定。

这些是我定义的约束。我使用带有 dict 而不是 NonlinearConstraints 对象的符号,因为似乎此方法接受严格的不等式(np.exp(-x[0] ** x[1]) 必须严格小于 1)。也许我误解了关于这个的文档。

def constraints(x):
  return [1 - np.exp(-(x[0]) ** x[1])]

为了最大化可能性,我最小化了负面可能性。

opt = minimize(lambda args: -to_minimize(args, data),
               x0=np.array((1, 1)), 
               constraints={'type': 'ineq', 'fun': constraints},
               bounds=np.array([(1e-15, 10), (1e-15, 10)]))

据我所知,这两个参数的选择方式永远不会导致我的代码失败。然而,该算法试图将 theta 移动到非常接近其下限并且 tau 非常接近其上限,以便对数变得不确定。

是什么导致我的代码失败?

两种形式的约束,即 NonlinearConstraintdict 约束都不支持严格的不等式。通常,人们因此使用 g(x) >= c + Ɛ 来模拟严格的不等式 g(x) > c,其中 Ɛ 是一个足够小的数字。

另请注意,不能保证每次迭代都位于可行区域内。在内部,大多数方法都试图通过简单的边界裁剪将其带回可行域。如果这不起作用,您可以尝试 NonlinearConstraints keep_feasible 选项,然后使用 trust-constr 方法:

import numpy as np
from scipy.optimize import NonlinearConstraint, minimize

def con_fun(x):
    return 1 - np.exp(-(x[0]) ** x[1])

# 1.0e-8 <= con_fun <= np.inf
con = NonlinearConstraint(con_fun, 1.0e-8, np.inf, keep_feasible=True)

x0 = np.array((1., 1.))
bounds = np.array([(1e-5, 10), (1e-5, 10)])

opt = minimize(lambda args: -to_minimize(args, data),
               x0=x0, constraints=(con,),
               bounds=bounds, method="trust-constr")