如何在 CPLEX Python 中设置包含指标函数的 objective 函数?

How do I setup an objective function in CPLEX Python containing indicator functions?

下面是objective函数:

这个想法是,已经对一系列证券进行了均值-方差优化。这为我们提供了目标投资组合的权重。现在假设投资者已经持有一个投资组合并且不想将他们的整个投资组合更改为目标投资组合。

令 w_0 = [w_0(1),w_0(2),...,w_0(N)] 为初始投资组合,其中w_0(i) 是投资组合的一部分 库存 i = 1,...,N。设 w_t = [w_t(1), w_t(2),...,w_t(N)] 为目标投资组合,即投资组合 重新平衡后最好拥有。该目标投资组合可以使用方差最小化等二次优化技术来构建。

objective决定最终组合w_f=[w_f(1),w_f(2),...,w_f(N)] 满足 以下特征:

要最小化的 objective 函数是通过将特征项 1 到 4 相加而创建的。

第一项是通过对最终投资组合和目标投资组合的权重绝对差求和得到的。

第二项是指标函数乘以用户指定惩罚的总和。指标函数为 y_{transactions}(i) 其中如果证券 i 的权重在初始投资组合和最终投资组合中不同则为 1,否则为 0。

第三项是最终投资组合总额 return 乘以用户指定的负惩罚,因为 objective 是最小化。

最后一项是最终投资组合中资产的数量(即计算最终投资组合中正权重数量的指标函数的总和)乘以用户指定的惩罚。

假设我们已经有了目标权重 target_w 我如何在 docplex python 库中设置这个优化问题?或者,如果有人熟悉 NAG 中的混合整数规划,那么知道如何在那里设置这样的问题也会很有帮助。

`
final_w = [0.]*n
final_w = np.array(final_w)
obj1 = np.sum(np.absolute(final_w - target_w)) 

pen_trans = 1.2
def ind_trans(final,inital):
    list_trans = []
    for i in range(len(final)):
        if abs(final[i]-inital[i]) == 0:
            list_trans.append(0)
        else:
            list_trans.append(1)
    return list_trans
obj2 = pen_trans*sum(ind_trans(final_w,initial_w))

pen_returns = 0.6
returns_np = np.array(df_secs['Return'])
obj3 = (-1)*np.dot(returns_np,final_w)

pen_count = 1.
def ind_count(final):
    list_count = []
    for i in range(len(final)):
        if final[i] == 0:
            list_count.append(0)
        else:
            list_count.append(1)
    return list_count
obj4 = sum(ind_count(final_w))

objective = obj1 + obj2 + obj3 + obj4

代码中的主要问题是 final_w 不是变量数组,而是数据数组。所以不会有什么需要优化的。要在 docplex 中创建变量数组,您必须执行以下操作:

from docplex.mp.model import Model
with Model() as m:
    final = m.continuous_var_list(n, 0.0, 1.0)

这会创建 n 可以取 0 到 1 之间的值的变量。有了它,您就可以开始工作了。例如:

    obj1 = m.sum(m.abs(initial[i] - final[i]) for i in range(n))

接下来 objective 事情变得更难了,因为您需要指标约束。为了简化这些约束的定义,首先定义一个辅助变量 delta,它给出股票之间的绝对差异:

    delta = m.continuous_var_list(n, 0.0, 1.0)
    m.add_constraints(delta[i] == m.abs(initial[i] - final[i]) for i in range(n))

接下来你需要一个指标变量,如果交易需要调整股票i:

    needtrans = m.binary_var_list(n)
    for i in range(n):
        # If needtrans[i] is 0 then delta[i] must be 0.
        # Since needtrans[i] is penalized in the objective, the solver will
        # try hard to set it to 0. It will only set it to 1 if delta[i] != 0.
        # That is exactly what we want
        m.add_indicator(needtrans[i], delta[i] == 0, 0)

有了它你可以定义第二个 objective:

    obj2 = pen_trans * m.sum(needtrans)

定义完所有 objective 后,您可以将它们的总和添加到模型中: m.minimize(obj1 + obj2 + obj3 + obj4) 然后求解模型并显示其解:

    m.solve()
    print(m.solution.get_values(final))

如果您(还)不清楚以上任何内容,那么我建议您查看 docplex 附带的许多示例以及(参考)文档。