【问题标题】:How to set bounds when minimizing using scipy使用 scipy 最小化时如何设置界限
【发布时间】:2018-06-10 00:36:25
【问题描述】:

我在一个 numpy 数组中有一些 data

我想根据以下规则使用线性函数对数据进行缩放:

  1. 平均值尽可能接近 65
  2. 最小值至少为 50

对于我的第一次尝试,我做了一个评分函数:

import numpy as np
from scipy.optimize import minimize
def score(x):
    return abs(np.mean(x[0]*data+x[1]) - 65) + abs(x[0]*np.min(data)+x[1] - 50)

我已经添加了 abs(x[0]*np.min(data)+x[1] - 50) 以试图让它满足规则 2。

然后我尝试了:

x0 = [0.85,0]
res = minimize(score,x0)
np.set_printoptions(suppress=True)
print res

这给出了:

fun: 4.8516444911893615
hess_inv: array([[ 0.0047, -0.1532],
       [-0.1532,  5.2375]])
      jac: array([-50.9628,  -2.    ])
message: 'Desired error not necessarily achieved due to precision loss.'
     nfev: 580
      nit: 2
     njev: 142
   status: 2
  success: False
        x: array([0.7408, 1.4407])

也就是说优化失败了。

我还想为系数设置界限,例如bounds = [(0.7,1.3),(-5,5)].

我的问题是,在缩放最小值至少为 50 的边界条件下运行优化的正确方法是什么?另外,我怎样才能使优化运行而不会失败?

【问题讨论】:

  • 查看本教程中对约束的最小化支持!我不明白你的评分方法。由于有两个组件并且由于不光滑,它看起来很破碎。取第一个,将 abs 替换为正方形或 l2-norm,并添加缺少的约束。

标签: python numpy optimization scipy


【解决方案1】:

考虑以下几点:

import numpy as np
from scipy.optimize import minimize

data = np.array([ 59. ,  59.5,  61. ,  61.5,  62.5,  63. ,  63. ,  65.5,  66.5,
    67. ,  68. ,  69. ,  69.5,  70.5,  70.5,  70.5,  71. ,  72. ,
    72. ,  73.5,  73.5,  74. ,  75. ,  75.5,  78. ,  79. ,  79. ,
    79. ,  79.5,  80.5,  80.5,  80.5,  80.5,  80.5,  82.5,  82.5,
    82.5,  83. ,  83. ,  83. ,  83. ,  83. ,  83.5,  83.5,  84. ,
    84.5,  84.5,  84.5,  86. ,  86. ,  86. ,  86.5,  86.5,  87.5,
    88. ,  88. ,  88.5,  89. ,  90. ,  90.5,  90.5,  90.5,  91. ,
    91.5,  91.5,  92. ,  92. ,  93. ,  93. ,  93. ,  93.5,  93.5,
    94. ,  94. ,  94. ,  94. ,  94. ,  94. ,  94.5,  94.5,  94.5,
    94.5,  95.5,  95.5,  95.5,  95.5,  95.5,  95.5,  96. ,  96. ,
    96. ,  96.5,  96.5,  96.5,  98. ,  98. ,  98. ,  98. ,  98. ,
    98. ,  98. ,  98. ,  98.5,  98.5,  98.5,  98.5,  98.5, 100. ,
   100. , 100. , 100. ])

def scale(data, coeffs):
    m,b = coeffs
    return (m * data) + b

def score(coeffs):
    scaled = scale(data, coeffs)
    # Penalty components
    p_1 = abs(np.mean(scaled) - 65)
    p_2 = max(0, (50 - np.min(scaled)))
    return p_1 + p_2

res = minimize(score, (0.85, 0.0), method = 'Powell')
#np.set_printoptions(suppress=True)
print(res)

post = scale(data, res.x)

print(np.mean(post))
print(np.min(post))
print(score(res.x))

输出:

方向:数组([[-3.05475495e-02, 2.62047576e+00], [7.54828106e-07,-6.47892698e-05]]) 乐趣:1.4210854715202004e-14 消息:“优化成功终止。” nfev:360 尼特:8 状态:0 成功:真 x:数组([0.55914442,17.02691959])
print(np.mean(post))  # 65.0
print(np.min(post))   # 50.0164406291
print(score(res.x))   # 1.42108547152e-14

一些事情:

  • 我添加了一个scale 辅助函数来稍微清理一下代码,因为我在score 函数中以及在末尾使用它来显示缩放后的数据。
  • 为清楚起见,score 函数已修复并分为两个单独的惩罚(每个要求一个)。它计算一次缩放向量(并将其称为scaled),然后计算惩罚分量。
  • 注意:由于max 调用,此评分函数在 min(data) = 50 附近有一个奇怪的非平滑区域。这可能会导致某些优化方法出现问题。
  • 我使用 Powell 算法是因为我以前使用过它,并且它在使用最小/最大运算符时遇到了类似的问题。维基百科says:

    该方法对于计算连续但复杂函数的局部最小值很有用,尤其是对于没有基础数学定义的函数,因为它不需要求导

    更熟悉优化方法的人可能会提出更好的替代方案。

  • (编辑)最后,关于您关于边界条件的问题。通常,当我们谈论边界条件时,我们谈论的是自变量的边界,我们正在优化的向量(这里是 coeffsx 的元素)——例如,“x[0] 必须小于 0”,或者“x[1] 必须介于 0 和 1 之间”——这不是您想要的。

【讨论】:

  • 谢谢你!我真的很抱歉,但我没有指定我也想为系数设置界限。例如。 bounds = [(0.7,1.3),(-5,5)]
  • 秘诀似乎就是一个接一个地尝试所有不同的方法,直到一个成功。
【解决方案2】:

对不起,如果我理解错了,但是根据这 2 条规则缩放数据是直截了当的线性代数:

e = np.mean(data)
m = e - np.min(data)

data * (65-50)/m + (65 - e*(65-50)/m)
# i.e. (data-e) * (65-50)/m + 65

这恰好意味着 65 和最小 50。

【讨论】:

  • 是的,抱歉,我没有完全说明问题。我正在寻找一种通用的优化方法,因为我最终会指定两个系数的界限。例如,第一个介于 0.7 和 1.3 之间,第二个介于 -5 和 5 之间。
猜你喜欢
  • 2015-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-30
  • 2015-02-18
相关资源
最近更新 更多