我想用scipy.optimize.minimize中的'COBYLA'方法解决优化问题,如下所示:
test = spopt.minimize(testobj, x_init, method='COBYLA', constraints=cons1)
y = test.x
print 'solution x =', y
但是,由于程序非常大,编写目标函数(和约束)的可伸缩方法是使用参数的通用索引。例如,如果我可以使用x['parameter1']
或x.param1
而不是x[0]
,则程序将更易于阅读和调试。我尝试将x
作为对象或pandas Series
编写一般索引,如x['parameter1']
,如下所示:
def testobj(x):
return x['a']**2 + x['b'] + 1
def testcon1(x):
return x['a']
def testcon2(x):
return x['b']
def testcon3(x):
return 1 - x['a'] - x['b']
x_init = pd.Series([0.1, 0.1])
x_init.index = ['a','b']
cons1 = ({'type': 'ineq', 'fun': testcon1}, \
{'type': 'ineq', 'fun': testcon2}, \
{'type': 'ineq', 'fun': testcon3})
但每当我将其传递到minimize
例程时,它都会抛出错误:
return x['a']**2 + x['b'] + 1
ValueError: field named a not found
如果我使用普通的numpy数组,它的效果非常好。也许我做得不对,但是我必须使用numpy数组而不是任何其他数据结构的最小化函数的限制?关于this topic的scipy文档提到最初的猜测必须是ndarray,但我很好奇例程如何调用参数,因为pandas Series
调用变量x[0]
或{ {1}}是等价的。
答案 0 :(得分:0)
正如您所说,scipy optimize使用numpy数组作为输入,而不是pandas Series。使用pandas系列初始化时,它会有效地将其转换为数组,因此您无法再按名称访问字段。
可能最简单的方法就是创建一个函数,每次调用它们时都会重新包装参数;例如:
def make_series(params):
return pd.Series(params, index=['a', 'b'])
def testobj(x):
x = make_series(x)
return x['a']**2 + x['b'] + 1
def testcon1(x):
x = make_series(x)
return x['a']
def testcon2(x):
x = make_series(x)
return x['b']
def testcon3(x):
x = make_series(x)
return 1 - x['a'] - x['b']
x_init = make_series([1, 1])
test = spopt.minimize(testobj, x_init, method='COBYLA', constraints=cons1)
print('solution x =', test.x)
# solution x = [ 1.38777878e-17 0.00000000e+00]