You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线性规划疑问:最优解为何是数据集最小值?如何调整?

问题描述

使用Pulp库编写医疗人力成本线性规划模型,目标是最小化人力成本/收入比,但求解后最优解始终取数据集中护士工时、医生工时的最小值,希望获得更合理的非最小值最优解,询问如何避免及可添加的额外约束。

附原代码:

import pandas as pd
from pulp import LpProblem, LpVariable, lpSum, LpMinimize, LpStatus

# Sample hospital data
data1 = {
'Hospital_ID': range(1, 11),
'Cost_Per_Nurse_Hour': [50, 55, 60, 45, 52, 58, 53, 49, 56, 54],
'Cost_Per_Doctor_Hour': [5000, 4500, 4000, 5500, 4800, 5100, 4700, 4900, 5200, 4600],
'Doctor_Hours': [100, 110, 95, 105, 108, 115, 98, 102, 107, 103],
'Nurse_Hours': [200, 190, 180, 210, 195, 205, 198, 215, 190, 200],
'Total_Patients': [150, 160, 145, 155, 148, 162, 149, 153, 158, 146],
'Hospital_Revenue': [80000, 75000, 82000, 78000, 79000, 81000, 79000, 80500, 79500, 81500],
}
data = pd.DataFrame(data1)

# Create the optimization problem
prob = LpProblem("Maximize_Margin_Labor", LpMinimize)

# Define decision variables 
nurse_hours_ = LpVariable("Nurse_Hours",lowBound=0, cat='Continuous')
doctor_hours_ = LpVariable("Doctor_Hours",lowBound=0, cat='Continuous')

# Objective function (minimize labor cost/ revenue ratio)
total_labor_cost = nurse_hours_ * lpSum(data.loc[i,"Cost_Per_Nurse_Hour"] for i in data.index) + doctor_hours_ * lpSum(data.loc[i,"Cost_Per_Doctor_Hour"] for i in data.index)
margin_labor = total_labor_cost / lpSum(data["Hospital_Revenue"])*100
prob += margin_labor

# Existing constraints
prob += nurse_hours_ >= 190  # minimum nurse hours observed
prob += nurse_hours_ <= 215  # maximum nurse hours observed
prob += doctor_hours_ >= 95  # minimum doctor hours observed
prob += doctor_hours_ <= 115  # maximum doctor hours observed
prob += nurse_hours_ - 2.1*doctor_hours_ <= 0  # 2.1 maximum observed Nurse Hours/Doctor Hours
prob += nurse_hours_ - 1.73*doctor_hours_ >= 0  # 1.73 minimum observed Nurse Hours/Doctor Hours

# Solve the problem
status = prob.solve()

# Print the results
print("Solver status:", LpStatus[status])

optimal_nurse_hours = int(nurse_hours_.value())
optimal_doctor_hours = int(doctor_hours_.value())

# Calculate labor cost and labor cost/revenue ratio for the optimal solutions
total_labor_cost = optimal_nurse_hours * lpSum(data["Cost_Per_Nurse_Hour"]) + optimal_doctor_hours * lpSum(data["Cost_Per_Doctor_Hour"])
margin_labor_percentage = (total_labor_cost / lpSum(data["Hospital_Revenue"])) * 100

print("Optimal Nurse Hours:", optimal_nurse_hours)  # 190 minimum nurse hours observed
print("Optimal Doctor Hours:", optimal_doctor_hours)  # 95 minimum doctor hours observed
print("Margin Labor Percentage:", margin_labor_percentage, "%")
原因分析

当前模型的目标是最小化人力成本占收入的比例,而护士和医生的单位工时成本均为正数,线性规划的特性会让目标函数在可行域的成本最低点(即工时下限)取得最优解——因为工时越少,总人力成本越低,自然满足最小化比例的目标。现有约束仅限定了工时的上下范围和比例关系,但没有从业务逻辑上限制“不能仅用最少人力”的要求。

可添加的额外约束

以下约束基于医疗业务逻辑设计,能避免模型取工时最小值,同时保证解的合理性:

1. 基于患者数量的服务能力约束

根据历史数据计算每个患者所需的最低护士/医生工时,确保人力能覆盖患者需求:

  • 计算历史平均护士工时/患者:avg_nurse_per_patient = data['Nurse_Hours'].sum() / data['Total_Patients'].sum()
  • 计算历史平均医生工时/患者:avg_doctor_per_patient = data['Doctor_Hours'].sum() / data['Total_Patients'].sum()
  • 添加约束:总护士工时 ≥ 总患者数 × 最低护士工时/患者;总医生工时 ≥ 总患者数 × 最低医生工时/患者

2. 工时的均值偏移约束

设定工时不能低于历史均值的一定比例,避免过度偏离合理区间:

  • 计算历史护士工时均值:avg_nurse_hours = data['Nurse_Hours'].mean()
  • 计算历史医生工时均值:avg_doctor_hours = data['Doctor_Hours'].mean()
  • 添加约束:nurse_hours_ >= avg_nurse_hours * 0.9(比如不低于均值的90%);doctor_hours_ >= avg_doctor_hours * 0.9

3. 避免边界解的硬约束(可选,较生硬)

直接设定工时变量高于现有最小值,比如:

  • nurse_hours_ >= 195(比原最小值190高)
  • doctor_hours_ >= 100(比原最小值95高)

4. 多目标优化约束

如果允许轻微增加成本,换取更合理的工时,可以引入加权多目标:

  • 原目标(最小化成本比例)为主目标,添加辅助目标(最大化工时或贴近均值),赋予权重平衡两者。比如:
    # 辅助目标:让工时贴近历史均值,权重可调整
    dev_nurse = abs(nurse_hours_ - avg_nurse_hours)
    dev_doctor = abs(doctor_hours_ - avg_doctor_hours)
    prob += margin_labor + 0.1*(dev_nurse + dev_doctor)  # 0.1为权重,可根据需求调整
    
修改后的示例代码

以下是添加了患者服务能力约束和均值偏移约束的完整代码:

import pandas as pd
from pulp import LpProblem, LpVariable, lpSum, LpMinimize, LpStatus

# Sample hospital data
data1 = {
'Hospital_ID': range(1, 11),
'Cost_Per_Nurse_Hour': [50, 55, 60, 45, 52, 58, 53, 49, 56, 54],
'Cost_Per_Doctor_Hour': [5000, 4500, 4000, 5500, 4800, 5100, 4700, 4900, 5200, 4600],
'Doctor_Hours': [100, 110, 95, 105, 108, 115, 98, 102, 107, 103],
'Nurse_Hours': [200, 190, 180, 210, 195, 205, 198, 215, 190, 200],
'Total_Patients': [150, 160, 145, 155, 148, 162, 149, 153, 158, 146],
'Hospital_Revenue': [80000, 75000, 82000, 78000, 79000, 81000, 79000, 80500, 79500, 81500],
}
data = pd.DataFrame(data1)

# Create the optimization problem
prob = LpProblem("Maximize_Margin_Labor", LpMinimize)

# Define decision variables 
nurse_hours_ = LpVariable("Nurse_Hours",lowBound=0, cat='Continuous')
doctor_hours_ = LpVariable("Doctor_Hours",lowBound=0, cat='Continuous')

# Objective function (minimize labor cost/ revenue ratio)
total_labor_cost = nurse_hours_ * lpSum(data.loc[i,"Cost_Per_Nurse_Hour"] for i in data.index) + doctor_hours_ * lpSum(data.loc[i,"Cost_Per_Doctor_Hour"] for i in data.index)
total_revenue = lpSum(data["Hospital_Revenue"])
margin_labor = (total_labor_cost / total_revenue) * 100
prob += margin_labor

# Existing constraints
prob += nurse_hours_ >= 190  # minimum nurse hours observed
prob += nurse_hours_ <= 215  # maximum nurse hours observed
prob += doctor_hours_ >= 95  # minimum doctor hours observed
prob += doctor_hours_ <= 115  # maximum doctor hours observed
prob += nurse_hours_ - 2.1*doctor_hours_ <= 0  # 2.1 maximum observed Nurse Hours/Doctor Hours
prob += nurse_hours_ - 1.73*doctor_hours_ >= 0  # 1.73 minimum observed Nurse Hours/Doctor Hours

# ---------------------- 添加的新约束 ----------------------
# 1. 基于患者数量的服务能力约束
total_patients = lpSum(data["Total_Patients"])
avg_nurse_per_patient = data['Nurse_Hours'].sum() / total_patients.value()
avg_doctor_per_patient = data['Doctor_Hours'].sum() / total_patients.value()
# 确保工时满足至少覆盖患者需求(可调整系数,比如0.95为95%的覆盖)
prob += nurse_hours_ >= total_patients * avg_nurse_per_patient * 0.95
prob += doctor_hours_ >= total_patients * avg_doctor_per_patient * 0.95

# 2. 均值偏移约束:不低于历史均值的90%
avg_nurse_hours = data['Nurse_Hours'].mean()
avg_doctor_hours = data['Doctor_Hours'].mean()
prob += nurse_hours_ >= avg_nurse_hours * 0.9
prob += doctor_hours_ >= avg_doctor_hours * 0.9
# ---------------------------------------------------------

# Solve the problem
status = prob.solve()

# Print the results
print("Solver status:", LpStatus[status])

optimal_nurse_hours = round(nurse_hours_.value(), 2)
optimal_doctor_hours = round(doctor_hours_.value(), 2)

# Calculate labor cost and labor cost/revenue ratio for the optimal solutions
total_labor_cost = optimal_nurse_hours * lpSum(data["Cost_Per_Nurse_Hour"]) + optimal_doctor_hours * lpSum(data["Cost_Per_Doctor_Hour"])
margin_labor_percentage = (total_labor_cost / total_revenue) * 100

print("Optimal Nurse Hours:", optimal_nurse_hours)
print("Optimal Doctor Hours:", optimal_doctor_hours)
print("Margin Labor Percentage:", round(margin_labor_percentage, 2), "%")
说明

修改后的模型会在满足业务合理性的前提下,寻找成本比例最低的解,不会再直接取工时最小值。你可以根据实际业务需求调整约束中的系数(比如覆盖比例、均值比例等),平衡成本和服务质量。

内容的提问来源于stack exchange,提问作者Heus

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:44:58