如何用scipy.optimize的LinearConstraint实现目标函数概率约束?
问题描述
现有一段实现Kelly-ECC方法的优化代码,希望添加一个约束:在概率分布p中至少(1-x)比例的场景下,对应场景的负对数收益项低于y,即约束形式为:
P[y ≥ -log(1 + r·f)] ≥ (1 - x)
原代码如下:
import random import numpy as np from scipy.optimize import minimize, LinearConstraint random.seed(123) # assumptions d = np.array([1.3, 10]) p = np.array([random.randint(700, 950) / 1000 for _ in range(100)]) scenarios = np.array([[1], [0]]) r = scenarios * d - 1 # returns per scenario def obj(f): return -1 * np.sum(p * np.log(np.sum(1 + r * f, axis=1))[:, None]) f0 = [0, 0] constr_1 = LinearConstraint(np.ones((1, 2)), lb=0, ub=1) constr_2 = LinearConstraint(np.eye(2), lb=0, ub=1) constraints = [constr_1, constr_2] res = minimize(fun=obj, x0=f0, method='trust-constr', constraints=constraints) print(res.x)
请问如何创建对应的约束?
解决方案
1. 约束转化为线性形式
你要求的约束可以转化为线性形式,从而用LinearConstraint实现:
原约束要求至少(1-x)概率的场景满足:
$$y \geq -\log(1 + r_i \cdot f)$$
对两边取指数并整理,得到等价的线性约束:
$$r_i \cdot f \geq e^{-y} - 1$$
其中$r_i \cdot f$是关于仓位$f$的线性表达式,完全符合LinearConstraint的要求。
2. 实现步骤
要保证满足约束的场景概率总和≥(1-x),我们可以筛选出概率最大的一批场景,强制它们满足上述线性约束:
- 设定参数x和y(比如x=0.1表示至少90%概率的场景需满足条件)
- 将场景按概率p从大到小排序,累加概率直到总和≥(1-x),筛选出这些高概率场景
- 对每个筛选出的场景,添加对应的线性约束
3. 修改后的完整代码
import random import numpy as np from scipy.optimize import minimize, LinearConstraint random.seed(123) # assumptions d = np.array([1.3, 10]) p = np.array([random.randint(700, 950) / 1000 for _ in range(100)]) scenarios = np.array([[1], [0]]) r = scenarios * d - 1 # returns per scenario # 设定约束参数:x=0.1 表示至少90%概率的场景满足条件,y=0.5 x = 0.1 y = 0.5 target_prob = 1 - x C = np.exp(-y) - 1 # 线性约束的下界 def obj(f): return -1 * np.sum(p * np.log(np.sum(1 + r * f, axis=1))[:, None]) f0 = [0, 0] # 原有约束:仓位总和0-1,单个仓位0-1 constr_1 = LinearConstraint(np.ones((1, 2)), lb=0, ub=1) constr_2 = LinearConstraint(np.eye(2), lb=0, ub=1) constraints = [constr_1, constr_2] # 添加新约束:筛选高概率场景并添加线性约束 # 按概率降序排序场景的索引 sorted_indices = np.argsort(p)[::-1] cum_prob = 0.0 selected_indices = [] for idx in sorted_indices: cum_prob += p[idx] selected_indices.append(idx) if cum_prob >= target_prob: break # 对每个选中的场景添加线性约束 r_i·f >= C for idx in selected_indices: # 将场景收益向量转为(1,2)格式适配LinearConstraint constr = LinearConstraint(r[idx].reshape(1, -1), lb=C, ub=np.inf) constraints.append(constr) # 执行优化 res = minimize(fun=obj, x0=f0, method='trust-constr', constraints=constraints) print(res.x)
说明
- 这种方法通过约束高概率场景满足条件,间接保证整体概率≥(1-x),是处理这类概率约束的常用近似手段
- 如果需要更严格的概率约束,可改用
NonlinearConstraint直接定义概率约束,但会增加优化的计算复杂度和难度
内容的提问来源于stack exchange,提问作者HJA24
相关产品推荐
相关产品推荐

