我正在尝试设计一个线性模型,其三个特征是三种不同元素的每周价格。我需要将这些价格结合起来以获得每周最便宜的组合。 我使用了 Scipy,当我输入数据时,最后只有 NaN,我不明白为什么。
这是我尝试过的:
import numpy as np
from scipy.optimize import linprog
wprices = np.array([205.5,215,225])
cprices = np.array([216.5,214,219])
bprices = np.array([184.5,192,202])
# Minimum percentage limits for each product
wprice_min_percentage = 0.25
cprice_min_percentage = 0.25
bprice_min_percentage = 0.25
# Number of weeks
num_weeks = len(wprices)
# Objective function coefficients (negative as we want to minimize the cost)
c = np.array([-wprices, -cprices, -bprices]).T
# Constraint matrix
A = np.array([[1, 1, 1]])
# Lower bounds for the constraints
b = np.array([1]) # Total percentage should be 1 (100%)
# Upper bounds for the constraints
A_ub = np.array([[-wprice_min_percentage, -cprice_min_percentage, -bprice_min_percentage]])
b_ub = np.array([-1]) # Each product's percentage should be greater than or equal to the minimum
# Solve the linear programming problem for each week
optimal_percentages = []
for week in range(num_weeks):
result = linprog(c[week], A_ub=A_ub, b_ub=b_ub, A_eq=A, b_eq=b)
if result.success:
optimal_percentages.append(result.x * 100)
else:
optimal_percentages.append([np.nan, np.nan, np.nan])
这是我解决这个问题的方法。
我想知道的第一件事是为什么
result.success
是False。因此,我将打印出 result
对象。
for week in range(num_weeks):
result = linprog(c[week], A_ub=A_ub, b_ub=b_ub, A_eq=A, b_eq=b)
print(result)
这会产生以下输出:
message: The problem is infeasible. (HiGHS Status 8: model_status is Infeasible; primal_status is At lower/fixed bound)
success: False
status: 2
fun: None
x: None
nit: 0
lower: residual: None
marginals: None
upper: residual: None
marginals: None
eqlin: residual: None
marginals: None
ineqlin: residual: None
marginals: None
这意味着我们的一些限制是矛盾的。让我们仔细看看我们的限制。
我注意到的第一件事是:
# Lower bounds for the constraints
b = np.array([1]) # Total percentage should be 1 (100%)
# [...]
result = linprog(c[week], A_ub=A_ub, b_ub=b_ub, A_eq=A, b_eq=b)
评论说
b
用作下限。然而,它作为 A
矩阵的等式约束传递。我建议修复此评论。
我接下来看的是我们的不平等约束:
A_ub = np.array([[-wprice_min_percentage, -cprice_min_percentage, -bprice_min_percentage]])
b_ub = np.array([-1]) # Each product's percentage should be greater than or equal to the minimum
# [...]
result = linprog(c[week], A_ub=A_ub, b_ub=b_ub, A_eq=A, b_eq=b)
让我们将其重写为数学方程,以便更好地了解正在发生的事情:
-wprice_min_percentage * x[0] + -cprice_min_percentage * x[1] + -bprice_min_percentage * x[2] <= -1
让我们简化这个方程:
wprice_min_percentage * x[0] + cprice_min_percentage * x[1] + bprice_min_percentage * x[2] >= 1
这向我们展示了注释所说的功能与代码实际功能之间的不匹配。评论说它单独限制了每个产品。然而,这表达了对所有元素之和的约束。
第二个问题是
min_percentage
变量位于该等式的错误一侧。
让我们在这个方程中代入一些示例值来说明原因。
wprice_min_percentage * x[0] + cprice_min_percentage * x[1] + bprice_min_percentage * x[2] >= 1
# Replace min_percentage with 0.25
0.25 * x[0] + 0.25 * x[1] + 0.25 * x[2] >= 1
# Replace x values with 0.33
0.25 * 0.33 + 0.25 * 0.33 + 0.25 * 0.33 >= 1
# Simplify
0.2475 >= 1
要解决此问题,我建议将
A_ub
和 b_ub
替换为以下内容:
A_ub = np.diag([-1, -1, -1])
b_ub = np.array([-wprice_min_percentage, -cprice_min_percentage, -bprice_min_percentage]) # Each product's percentage should be greater than or equal to the minimum
(旁注:
bounds
的linprog()
参数也可以用在这里,而且更容易使用。)
让我们尝试重新运行代码,看看会得到什么。
>>> print(optimal_percentages)
[array([25., 50., 25.]), array([50., 25., 25.]), array([50., 25., 25.])]
它是尽可能多地购买一种资源,并尽可能少地购买所有其他资源。如果目标是最小化成本,那么这看起来是合理的。让我们同时看看成本和百分比。
for week in range(num_weeks):
print("week", week)
print(optimal_percentages[week], c[week])
输出:
week 0
[25. 50. 25.] [-205.5 -216.5 -184.5]
week 1
[50. 25. 25.] [-215. -214. -192.]
week 2
[50. 25. 25.] [-225. -219. -202.]
似乎每周都会购买最昂贵的选择。要找出原因,让我们看看顶部的评论:
# Objective function coefficients (negative as we want to minimize the cost)
c = np.array([-wprices, -cprices, -bprices]).T
将其与 文档进行比较:
线性规划:最小化受线性等式和不等式约束的线性目标函数。
换句话说,linprog 已经最小化了目标函数。如果我们添加一个负号,它就会开始最大化价格。
修复方法是删除负号:
# Objective function coefficients (negative as we want to minimize the cost)
c = np.array([wprices, cprices, bprices]).T
最终完整代码:
import numpy as np
from scipy.optimize import linprog
wprices = np.array([205.5,215,225])
cprices = np.array([216.5,214,219])
bprices = np.array([184.5,192,202])
# Minimum percentage limits for each product
wprice_min_percentage = 0.25
cprice_min_percentage = 0.25
bprice_min_percentage = 0.25
# Number of weeks
num_weeks = len(wprices)
# Objective function coefficients (negative as we want to minimize the cost)
c = np.array([wprices, cprices, bprices]).T
# Constraint matrix
A = np.array([[1, 1, 1]])
# Equality constraints for A
b = np.array([1]) # Total percentage should be 1 (100%)
# Upper bounds for the constraints
A_ub = np.diag([-1, -1, -1])
b_ub = np.array([-wprice_min_percentage, -cprice_min_percentage, -bprice_min_percentage]) # Each product's percentage should be greater than or equal to the minimum
# Solve the linear programming problem for each week
optimal_percentages = []
for week in range(num_weeks):
result = linprog(c[week], A_ub=A_ub, b_ub=b_ub, A_eq=A, b_eq=b)
if result.success:
optimal_percentages.append(result.x * 100)
else:
optimal_percentages.append([np.nan, np.nan, np.nan])
for week in range(num_weeks):
print("week", week)
print(optimal_percentages[week], c[week])