使用GEKKO进行大量变量,界限和约束的优化

时间:2019-12-20 02:39:43

标签: optimization mathematical-optimization portfolio gekko

我想用GEKKO解决一个优化问题。最初的问题是您拥有一个线性目标函数,其中包含数千个变量,约束(其中一些是非线性的)和边界。有人建议我使用GEKKO,由于我不完全了解它的机制,因此在实现它时遇到了一些问题。我不断收到object of type 'int' has no len()错误。我已经简化了问题,所以现在只有20个varialbes,没有约束,但是必须遵守10个边界。通过这种方式,我认为我可以隔离并确定错误源。代码如下:

import pandas as pd
import numpy as np
import copy as cp
from gekko import GEKKO  
from scipy.optimize import minimize

df_uni = pd.read_csv(r'D:\US\IIT\lectures_textbooks\QIS\week_4\universe_sets.csv')
df_uni["begin_wt"]=np.zeros(10)

#df_holding=df_uni
df_holding=cp.deepcopy(df_uni)

x_holding=np.array([0.1,0.25,0.2,0.2,0.05,0.05,0.1,0.15,-0.05,-0.05])

df_holding["begin_wt"]=x_holding

df_holding.loc[df_holding['begin_wt'] >0, "up_limit"] = df_holding['begin_wt']
df_holding.loc[df_holding['begin_wt'] <0, "up_limit"] = 0

Alpha_pickup=3
df_holding.loc[df_holding['begin_wt'] >0, "Alpha"] = df_holding['Alpha']+Alpha_pickup
df_holding.loc[df_holding['begin_wt'] <0, "Alpha"] = df_holding['Alpha']-Alpha_pickup


df_holding.loc[df_holding['begin_wt'] >0, "low_limit"] = 0
df_holding.loc[df_holding['begin_wt'] <0,"low_limit"]=df_holding['begin_wt']


df_holding=df_holding.drop("begin_w",axis=1)
df_uni=df_uni.drop("begin_w",axis=1)

sect_offset=0.1
lncap_offset=0.1

sect1=sum(df_uni.loc[df_holding['Sector_1'] ==1]['ben_wt'])
sect2=sum(df_uni.loc[df_holding['Sector_2'] ==1]['ben_wt'])

lncap1=sum(df_uni.loc[df_holding['Sector_1'] ==1]['lncap'])
lncap2=sum(df_uni.loc[df_holding['Sector_2'] ==1]['lncap'])


list_uni_alpha=list(df_uni['Alpha'])
list_holding_alpha=list(df_holding['Alpha'])
bind_list_alpha=list_uni_alpha+list_holding_alpha

#x=[1 for i in range(20)]

def objective(x):
    l=0
    sum_of_Alpha=0
    for i in bind_list_alpha:
        sum_of_Alpha=sum_of_Alpha+x[l]*i
        print(sum_of_Alpha)
        l=l+1
    return sum_of_Alpha
# constraints always writing them in terms of f(x)>0
# consolidated weights are bound 
# security offsets
uni_begin=list(df_uni['begin_wt'])
holding_begin=list(df_holding['begin_wt'])
#initial guess
ig=cp.deepcopy(uni_begin+holding_begin)

m=GEKKO()
x = m.Array(m.Var,(20)) 
x_holding=x[10:20]
i=0
#bounds
for xi in x_holding:

    xi.value = x_holding[i]
    xi.lower = df_holding['low_limit'][i]
    xi.upper = df_holding['up_limit'][i]
    i = i + 1

m.Obj(objective(x))
m.solve()
print(x)

请原谅我加入了似乎无关的代码块。但是,为了给熟悉投资组合构建的思想提供背景,我实际上是在尝试构建股票投资组合。 obejctve函数是股票的alpha的线性组合。 “持有”是指您当前持有的股票,而“宇宙”是您可以投资的大量股票。我正在积极管理,所以我倾向于偏重于那些我认为良好的股票而低于那些股票。我认为这不好。但是,当然我不希望我的投资组合看起来与基准有很大不同,因为那会使投资组合承担很多系统性风险。因此,您将在代码结尾看到这些约束。我一直在寻找可以容纳以aX = b形式编写的约束的优化器,其中a和b都像数组,而X是矩阵。但就目前而言,我认为这个特定的优化程序将对我同样有用!

谢谢!

2 个答案:

答案 0 :(得分:2)

Gekko的functions to load dense or sparse matrices for linear programming problems格式为:

min c x
s.t. A1 x = b1
     A2 x < b2 

如果矩阵中有很多零,这是一个非常大规模的问题,那么稀疏形式可能是最有效的。这是您编写模型方程式的方式:

from gekko import GEKKO
m = GEKKO()
x1 = m.Var(lb=0, ub=5) # Product 1
x2 = m.Var(lb=0, ub=4) # Product 2
m.Maximize(100*x1+125*x2) # Profit function
m.Equation(3*x1+6*x2<=30) # Units of A
m.Equation(8*x1+4*x2<=44) # Units of B
m.solve(disp=False)
p1 = x1.value[0]; p2 = x2.value[0]
print ('Product 1 (x1): ' + str(p1))
print ('Product 2 (x2): ' + str(p2))
print ('Profit        : ' + str(100*p1+125*p2))

如果您想使用Gekko的内置线性方程式和二次目标模型,则以密集矩阵形式为:

from gekko import GEKKO
m = GEKKO(remote=False)
c = [100, 125]
A = [[3, 6], [8, 4]]
b = [30, 44]
x = m.qobj(c,otype='max')
m.axb(A,b,x=x,etype='<')
x[0].lower=0; x[0].upper=5
x[1].lower=0; x[1].upper=4
m.options.solver = 1
m.solve(disp=True)
print ('Product 1 (x1): ' + str(x[0].value[0]))
print ('Product 2 (x2): ' + str(x[1].value[0]))
print ('Profit        : ' + str(m.options.objfcnval))

以稀疏矩阵形式为:

# solve with GEKKO and sparse matrices
import numpy as np
from gekko import GEKKO
m = GEKKO(remote=False)
# [[row indices],[column indices],[values]]
A_sparse = [[1,1,2,2],[1,2,1,2],[3,6,8,4]]
# [[row indices],[values]]
b_sparse = [[1,2],[30,44]]
x = m.axb(A_sparse,b_sparse,etype='<',sparse=True)
# [[row indices],[values]]
c_sparse = [[1,2],[100,125]]
m.qobj(c_sparse,x=x,otype='max',sparse=True)
x[0].lower=0; x[0].upper=5
x[1].lower=0; x[1].upper=4
m.solve(disp=True)
print(m.options.OBJFCNVAL)
print('x: ' + str(x))

sparse matrices[rows,columns,values]的形式存储在坐标列表(COO)中。我更喜欢压缩稀疏行(CSR)形式的矩阵,但如果问题不严重并且接近计算机的内存限制,则可以使用COO。如果您的问题是线性的,那么您可能还想看看CPLEX,Gurobi或Xpress Mosel求解器,因为它们是专用的线性求解器,而不是使用混合整数非线性编程求解器的Gekko。他们应该给出相同的答案,但是混合整数线性规划求解器会更快。

答案 1 :(得分:2)

xi.value = x_holding[i]可能有问题,其中gekko需要一个初始猜测值,该值是一个数字,而不是gekko变量。这是您的问题的简化版本:

from gekko import GEKKO 
import numpy as np

def objective(x):
    return m.sum(x)

m=GEKKO()
x = m.Array(m.Var,(20)) 
for i,xi in enumerate(x[0:10]):
    xi.value = 0.5
    xi.lower = 0
    xi.upper = i
for i,xi in enumerate(x[10:]):
    xi.value = 0.5
    xi.lower = 0
    xi.upper = i

m.Maximize(objective(x))
m.solve()
print(x)

这提供了解决方案[0,1,...,8,9,0,1,...,8,9],因为所有变量都使用m.Maximize达到上限。它们都以m.Minimize达到最小值。我同意另一个答案,即使用稀疏矩阵的m.axbm.qobj函数来解决投资组合优化(特别是对于大规模问题)将更加有效。