Scipy线性规划(含松弛变量):最小化B类变量加权结果偏差
线性规划中惩罚B变量加权结果最大差异的实现方案
你现在的需求是在原有线性规划最小化目标函数的基础上,让B1、B2、B3、B4四个变量加权后的结果(即Bi·x)之间的最大绝对差异尽可能小。之前尝试的成对固定上限约束没法动态惩罚这个最大值,这里我们用线性规划处理最大绝对偏差的标准方法来解决。
核心思路
要惩罚最大差异,我们可以引入一个额外的非负变量t,这个t代表所有Bi·x之间的最大绝对差异。然后把t加入目标函数并赋予惩罚系数(比如λ,值越大说明你越看重缩小差异),这样优化过程会同时最小化原目标和t的大小,从而动态控制最大差异。
对应的约束条件需要转化为线性形式:对每一对Bi和Bj,满足
(Bi - Bj)·x ≤ t(Bj - Bi)·x ≤ t
这两个式子合起来等价于|Bi·x - Bj·x| ≤ t,同时t必须非负(因为绝对差异不可能是负数)。
示例代码
下面是修改后的完整代码,包含差异惩罚的逻辑:
import numpy as np from scipy.optimize import linprog from numpy.linalg import multi_dot as dot import pandas as pd # 初始化数据集 df = pd.DataFrame(np.array([[10, 10, 10, 10], [0.8415, 0.9547, 0.9460, 0.9512], [0.9895, 0.9443, 0.9042, 0.9634], [0.9460, 0.9443, 0.8101, 0.9199], [0.9878, 0.8362, 0.9233, 0.7909]]), columns=['Center1', 'Center2', 'Center3', 'Center4'], index=['A', 'B1', 'B2', 'B3', 'B4']) # 原目标函数的系数 lamb = np.array([0.1, 1, 1, 1, 1]) c_original = dot([lamb, df.values]).squeeze() # ---------------------- 新增:处理最大差异惩罚 ---------------------- # 惩罚系数:λ越大,越优先缩小B变量之间的差异,可根据需求调整 penalty_lambda = 10 # 生成B变量的成对组合(i<j,避免重复约束) B_indices = ['B1', 'B2', 'B3', 'B4'] pairs = [(i, j) for i in range(len(B_indices)) for j in range(i+1, len(B_indices))] # 构建约束矩阵A_ub和约束向量b_ub A_ub_rows = [] b_ub_rows = [] for i, j in pairs: Bi = df.loc[B_indices[i]].values Bj = df.loc[B_indices[j]].values # 约束1:(Bi - Bj)·x - t ≤ 0 row = np.concatenate([Bi - Bj, [-1]]) A_ub_rows.append(row) b_ub_rows.append(0) # 约束2:(Bj - Bi)·x - t ≤ 0 row = np.concatenate([Bj - Bi, [-1]]) A_ub_rows.append(row) b_ub_rows.append(0) A_ub = np.array(A_ub_rows) b_ub = np.array(b_ub_rows) # 新的目标函数:原目标 + 惩罚系数 * t c = np.concatenate([c_original, [penalty_lambda]]) # 变量边界:原x的边界不变,t≥0 x_bounds = list(zip([-3, -3, -3, -3], [3, 3, 3, 3])) t_bound = (0, None) # t必须非负 bounds = x_bounds + [t_bound] # ---------------------- 求解线性规划 ---------------------- res = linprog(c=c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, options={"disp": True}) # 提取结果 x = res.x[:4] # 原权重向量 t = res.x[4] # 最大绝对差异的理论上限 # 计算B变量的加权结果 B_weighted = df.loc[B_indices, :].dot(x) print("\nB变量加权结果:") print(B_weighted) print(f"\n最大绝对差异上限t:{t:.4f}") print(f"实际最大绝对差异:{np.max(B_weighted) - np.min(B_weighted):.4f}")
关键说明
- 惩罚系数
penalty_lambda:可根据需求调整。如果希望B变量结果尽可能接近,就调大这个值;如果更看重原目标函数的最小化,就调小它。 - 约束构建:只生成
i<j的成对组合,避免重复约束,同时把绝对值条件拆成两个线性约束,符合线性规划的要求。 - 变量扩展:把
t加入变量向量,新变量为[x1, x2, x3, x4, t],并设置t≥0的边界。
运行代码后,你会看到B变量的加权结果差异会比之前小很多,t的值就是优化后得到的最大绝对差异的理论上限,实际的最大差异会等于或略小于t(最优解会让t刚好匹配实际最大差异)。
内容的提问来源于stack exchange,提问作者Zhubarb




