SciPy约束优化n>1000时收敛至初始值的问题求助
我用SciPy的optimize工具处理10万条观测值的约束优化任务,但当观测数n>1000时,优化结果会收敛到初始值。比如500条观测值能得到良好的局部最小值,但n趋近1000时,优化值和初始值完全一致。
目标函数与约束条件代码
目标函数:
def objective(x): return np.sum(np.array([-TU_array[i]*(NR_fn(x[i])-LS_fn(x[i],pd_array[i])) for i in range(0,len(x))])) # where def NR_fn(x): R = (1.99525947856706E-13*x**3-0.000000299925*x**2+0.137682384749*x+3648.729074580060) return R def LS_fn(x,pd): L =x*pd return L
约束条件:
def constraint1(x): return np.sum(x)-df["creditlimit"].sum() def constraint3(x): return np.sum(np.array([LS_fn(x[i],pd_array[i]) for i in range(0,len(x))]))-525000 b = (df["creditlimit"].min(),df["creditlimit"].max()) bnds = (b,)*len(df) con1 = {'type': 'eq', 'fun': constraint1} # con2 = {'type': 'eq', 'fun': constraint2} con3 = {'type': 'eq', 'fun': constraint3} cons = ([con1,con3]) x0 = np.array(df["creditlimit"]) solution = minimize(objective,x0,method='SLSQP', bounds=bnds,constraints = cons, options={'maxiter': 200, 'disp': True}) x = solution.x
我试过修改约束条件和函数形式,结果还是和初始值一致,该怎么解决?有没有其他工具适合这个函数的优化?
一、优化现有SciPy SLSQP的实现
目标函数向量化改造
当前循环遍历每个元素的写法,在n>1000时计算效率极低,会导致优化器因计算量过大提前终止。改成完全向量化形式:def objective(x): nr_vals = NR_fn(x) ls_vals = x * pd_array return np.sum(-TU_array * (nr_vals - ls_vals))约束条件也同步去掉循环:
def constraint3(x): return np.sum(x * pd_array) - 525000向量化能大幅提升计算速度,让优化器在迭代次数内完成足够的搜索步骤。
调整SLSQP迭代参数
- 增大
maxiter:当前200次迭代对高维问题可能不足,尝试调到500或1000; - 收紧容差:设置
ftol=1e-8、eps=1e-6,让优化器更严格判断收敛状态; - 开启详细日志:添加
iprint=2到options,查看迭代过程中目标函数和约束的变化,确认是真收敛还是提前终止。
- 增大
扰动初始点
你的初始点x0刚好满足约束1的等式条件,如果同时接近约束3的边界,优化器会直接判定当前点为可行域极值点。给初始点加小扰动:x0 = np.array(df["creditlimit"]) + np.random.normal(0, 10, size=len(x0))让优化器从非约束边界点开始搜索。
二、换用更适配的优化工具
SciPy L-BFGS-B结合拉格朗日乘子
L-BFGS-B更适合高维问题,可将等式约束转化为拉格朗日函数重新构造目标:def lagrangian(x, lambda1, lambda3): obj_val = objective(x) con1_val = constraint1(x) con3_val = constraint3(x) return obj_val + lambda1 * con1_val + lambda3 * con3_val对x、lambda1、lambda3联合优化,注意参数初始化的合理性。
用CVXPY/ Pyomo调用专业求解器
这类建模框架能自动适配大规模问题,推荐用IPOPT求解器:import cvxpy as cp x = cp.Variable(len(df), bounds=bnds) objective = cp.sum(-TU_array * (NR_fn(x) - x * pd_array)) constraints = [ cp.sum(x) == df["creditlimit"].sum(), cp.sum(x * pd_array) == 525000 ] prob = cp.Problem(cp.Minimize(objective), constraints) prob.solve(solver=cp.IPOPT, max_iter=1000) x_opt = x.valueIPOPT在高维非线性约束问题上的稳定性远优于SLSQP。
并行化优化(针对10万级观测)
超大规模问题可借助dask实现并行计算,或用mpi4py做分布式优化,降低单节点计算压力。
三、利用问题结构简化求解
你的目标函数是可分离的(每个x[i]的贡献独立,仅约束为总和形式),可以用拉格朗日对偶法分解为单变量优化问题,先求解每个x[i]的最优解表达式,再通过约束条件求解拉格朗日乘子,避免直接优化高维变量,这是处理此类问题最高效的思路。
内容的提问来源于stack exchange,提问作者Deepak

