You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Scipy线性规划(含松弛变量):最小化B类变量加权结果偏差

线性规划中惩罚B变量加权结果最大差异的实现方案

你现在的需求是在原有线性规划最小化目标函数的基础上,让B1、B2、B3、B4四个变量加权后的结果(即Bi·x)之间的最大绝对差异尽可能小。之前尝试的成对固定上限约束没法动态惩罚这个最大值,这里我们用线性规划处理最大绝对偏差的标准方法来解决。

核心思路

要惩罚最大差异,我们可以引入一个额外的非负变量t,这个t代表所有Bi·x之间的最大绝对差异。然后把t加入目标函数并赋予惩罚系数(比如λ,值越大说明你越看重缩小差异),这样优化过程会同时最小化原目标和t的大小,从而动态控制最大差异。

对应的约束条件需要转化为线性形式:对每一对BiBj,满足

  • (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

火山引擎 最新活动