scipy-optimize-minimize 不执行优化 - CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL

scipy-optimize-minimize does not perform the optimization - CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL

我正在尝试最小化定义如下的函数:

utility(decision) = decision * (risk - cost)

其中变量采用以下形式:

decision = binary array

risk = array of floats

cost = constant

我知道解决方案将采用以下形式:

decision = 1 if (risk >= threshold)

decision = 0 otherwise

因此,为了最小化这个函数,我可以假设我将函数效用转换为仅依赖于这个阈值。我对 scipy 的直接翻译如下:

def utility(threshold,risk,cost):

     selection_list = [float(risk[i]) >= threshold for i in range(len(risk))]
     v = np.array(risk.astype(float)) - cost

     total_utility = np.dot(v, selection_list)

     return -1.0*total_utility

result = minimize(fun=utility, x0=0.2, args=(r,c),bounds=[(0,1)], options={"disp":True} )

这给了我以下结果:

fun: array([-17750.44298655])  hess_inv: <1x1 LbfgsInvHessProduct with
dtype=float64>
jac: array([0.])   
message: b'CONVERGENCE: NORM_OF_PROJECTED_GRADIENT_<=_PGTOL'
nfev: 2
nit: 0    status: 0   success: True
x: array([0.2])

但是,我知道结果是错误的,因为在这种情况下它必须等于 cost。最重要的是,无论我使用什么 x0,结果总是 returns 它。查看结果,我发现 jacobian=0 并且没有正确计算 1 次迭代。

更彻底地研究函数。我绘制它并观察到它在边界的限制上不是凸的,但我们可以清楚地看到最小值 0.1。但是,无论我将边界调整多少只在凸起部分,结果仍然是一样的。

我该怎么做才能最小化这个功能?

错误消息告诉您梯度在某个点太小,因此在数值上与零相同。这可能是由于您在计算 selection_list 时所做的阈值处理。你说 float(risk[i]) >= threshold,几乎所有地方的导数都是 0。因此,几乎每个起始值都会给您收到警告。

一个解决方案可能是对阈值操作应用一些平滑。因此,您可以使用连续函数代替 float(risk[i]) >= threshold

def g(x):
    return 1./(1+np.exp(-x))

有了这个函数,您可以将阈值操作表示为 g((risk[i] - threshold)/a),其中一个参数aa 越大,这个修改后的误差函数就越接近您目前所做的。在 a=20 左右,您可能会拥有与现在几乎相同的东西。因此,您将导出一系列解决方案,从 a=1 开始,然后将该解决方案作为 a=2 相同问题的起始值,将该解决方案作为 a=2 问题的起始值=20=],等等。在某些时候,您会注意到更改 a 不会再更改解决方案,您就完成了。