使用常规数组索引进行scipy.optimize.minimize

时间:2015-10-31 17:57:41

标签: optimization pandas indexing scipy minimize

我想用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}}是等价的。

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]