使用scipy求解带分组求和约束的最小化优化问题
带分组求和约束的权重优化实现
你的优化目标是最小化 $\frac{\sum_i (w_i - uw_i)^2}{\sum uw_i}$,由于分母$\sum uw_i$是与$w_i$无关的固定常数,优化过程等价于最小化$\sum_i (w_i - uw_i)^2$,不需要额外对分母做处理。
scipy.optimize.lsq_linear仅支持变量上下界约束,无法实现分组求和类的线性不等式约束,需要换用支持通用线性约束的优化接口求解,三个约束可以全部覆盖:
- 边界约束:$0.05 \leq w_i \leq ul_i$
- 分组约束:每个sector code对应的$w_i$之和$\leq 0.5$
完整实现代码
import pandas as pd import numpy as np from scipy.optimize import minimize, LinearConstraint, Bounds # 读取原始数据 df = pd.read_csv("https://raw.githubusercontent.com/norhther/datasets/main/data(1).csv") df = df.drop("Unnamed: 0", axis=1) sample_count = len(df) # 1. 配置变量边界约束(对应w的上下限要求) uw = df["uw"].values w_lower = np.full(sample_count, 0.05) w_upper = df["ul"].values bound_constraint = Bounds(lb=w_lower, ub=w_upper) # 2. 构造sector分组求和的线性约束 unique_sectors = df["sector"].unique() sector_constraint_matrix = np.zeros((len(unique_sectors), sample_count)) for row_idx, sector_val in enumerate(unique_sectors): sector_mask = (df["sector"] == sector_val).values sector_constraint_matrix[row_idx, sector_mask] = 1 # 约束定义:组内和无下限,上限0.5 sector_sum_constraint = LinearConstraint( sector_constraint_matrix, lb=-np.inf, ub=0.5 ) # 3. 定义优化目标函数 def least_square_objective(w): return np.sum((w - uw) ** 2) # 4. 生成初始值:将原始uw裁剪到边界范围内作为热启动,提升求解速度 w_init = np.clip(uw, w_lower, w_upper) # 5. 求解优化问题 opt_result = minimize( least_square_objective, x0=w_init, method="trust-constr", bounds=bound_constraint, constraints=[sector_sum_constraint], tol=1e-8 ) # 将最优解写回DataFrame df["w_i"] = opt_result.x
结果校验
求解完成后可以运行以下代码确认所有约束均满足,判断条件中预留了1e-6的浮点误差容忍空间,避免数值计算精度问题导致误判:
# 校验上下界约束 bound_check = (df["w_i"] >= 0.05 - 1e-6).all() and (df["w_i"] <= df["ul"] + 1e-6).all() print(f"上下界约束满足:{bound_check}") # 校验sector分组和约束 sector_sum = df.groupby("sector")["w_i"].sum() sector_check = (sector_sum <= 0.5 + 1e-6).all() print(f"分组求和约束满足:{sector_check}")
说明
- 热启动初始值可以大幅减少优化迭代次数,万级样本量下该实现可以在数秒内完成求解
- 如果样本量超过10万,可以替换为cvxpy等专用凸优化库进一步提升求解效率
- 目标函数的常数分母不会改变最优解的取值,因此优化时省略不影响结果正确性
内容的提问来源于stack exchange,提问作者Norhther
相关产品推荐
相关产品推荐

