使用scipy.optimize.minimize()的Ineq和eq约束

时间:2016-01-16 00:36:49

标签: python scipy mathematical-optimization

我试图理解scipy.optimize.minimize中的约束行为:

首先,我创建了4个资产和100个退货方案。平均回报资金最好是D > B > A > C

#seed first 
np.random.seed(1)

df_returns = pd.DataFrame(np.random.rand(100,4) - 0.25, columns =list('ABCD'))
df_returns.head()

    A           B           C           D
0   0.167022    0.470324    -0.249886   0.052333
1   -0.103244   -0.157661   -0.063740   0.095561
2   0.146767    0.288817    0.169195    0.435220
3   -0.045548   0.628117    -0.222612   0.420468
4   0.167305    0.308690    -0.109613   -0.051899

和一组权重

weights = pd.Series([0.25, 0.25, 0.25, 0.25], index=list('ABCD'))

    0
A   0.25
B   0.25
C   0.25
D   0.25

我们创建了一个目标函数:

def returns_objective_function(weights, df_returns):
    result = -1. * (df_returns * weights).mean().sum()
    return result

和约束和界限

cons = ({'type': 'eq', 'fun': lambda weights: np.sum(weights) -1  })
bnds = ((0.01, .8), (0.01, .8), (0.01, .8), (0.01, .75))

让我们优化

optimize.minimize(returns_objective_function, weights, (df_returns),
                              bounds=bnds, constraints=cons, method= 'SLSQP')

And we get success.
  status: 0
 success: True
    njev: 8
    nfev: 48
     fun: -0.2885398923185326
       x: array([ 0.01,  0.23,  0.01,  0.75])
 message: 'Optimization terminated successfully.'
     jac: array([-0.24384782, -0.2789166 , -0.21977262, -0.29300382,  0.        ])
     nit: 8

现在我希望从基本不等式开始添加约束:

scipy.optimize.minimize文档说明

  

等式约束意味着约束函数结果为零,而不等式意味着它是非负的。

cons = ( 
        {'type': 'eq', 'fun': lambda weights: np.sum(weights) -1  }
        ,{'type': 'ineq', 'fun': lambda weights: np.sum(weights) + x}
)

根据x,我会遇到意想不到的行为。

x = -100

根据边界,权重最大可以是3.15,当然,必须由第一个等式约束np.sum(weights) - 1加1,但结果,np.sum(weights) + x总是负数。我相信找不到解决方案,但scipy.optimize.minimize会成功。

1 个答案:

答案 0 :(得分:0)

使用更简单的模型我会得到相同的行为:

x = [1,2] 
optimize.minimize(
    lambda x: x[0]**2+x[1]**2, 
    x, 
    constraints = (
        {'type':'eq','fun': lambda x: x[0]+x[1]-1},
        {'type':'ineq','fun': lambda x: x[0]-2}
                  ),
    bounds = ((0,None),(0,None)),
    method='SLSQP')

结果:

   nfev: 8
    fun: 2.77777777777712
    nit: 6
    jac: array([  3.33333334e+00,   2.98023224e-08,   0.00000000e+00])
      x: array([  1.66666667e+00,   1.39888101e-14])
success: True
message: 'Optimization terminated successfully.'
 status: 0
   njev: 2

应该有一些标志,这是一个不可行的解决方案。

SLSQP也可从R:

获得
> slsqp(c(1,2),
+       function(x) {x[1]^2+x[2]^2},
+       heq=function(x){x[1]+x[2]-1},
+       hin=function(x){x[1]-2},
+       lower=c(0,0))
$par
[1] 1.666667e+00 4.773719e-11

$value
[1] 2.777778

$iter
[1] 105

$convergence
[1] -4

$message
[1] "NLOPT_ROUNDOFF_LIMITED: Roundoff errors led to a breakdown of the optimization algorithm. In this case, the returned minimum may still be useful. (e.g. this error occurs in NEWUOA if one tries to achieve a tolerance too close to machine precision.)"

至少我们在这里看到一些警告信号。