使用Linear Programming优化员工排班时遇IndexError问题求助
员工排班线性规划优化报错排查与修复
问题背景
使用Python的Pulp库基于给定DataFrame实现员工排班优化时,执行目标函数prob += lpSum([w[j] * y[j] for j in range(n)])触发IndexError: index 1 is out of bounds for axis 0 with size 1错误。
原始数据
Time Windows Shift 1 Shift 2 Shift 3 Shift 4 Workers Required 0 6:00 - 9:00 1 0 0 1 55.0 1 9:00 - 12:00 1 0 0 0 46.0 2 12:00 - 15:00 1 1 0 0 59.0 3 15:00 - 18:00 0 1 0 0 23.0 4 18:00 - 21:00 0 1 1 0 60.0 5 21:00 - 24:00 0 0 1 0 38.0 6 24:00 - 3:00 0 0 1 1 20.0 7 3:00 - 6:00 0 0 0 1 30.0 8 Wage_Rate 135 140 190 188 0.0
错误栈
Traceback (most recent call last): Cell In[197], line 1 prob += lpSum([w[j] * y[j] for j in range(n)]) Cell In[197], line 1 in <listcomp> prob += lpSum([w[j] * y[j] for j in range(n)]) IndexError: index 1 is out of bounds for axis 0 with size 1
错误定位
- 薪资数组维度与来源错误:代码先执行
df.drop(df.tail(1).index,inplace=True)删除了薪资行,后续用last_row = df.iloc[-1:,1:]获取的是最后一个时间段的数据,而非薪资;同时iloc[-1:,1:]返回二维数组,直接用w[j]访问会因维度不匹配报错。 - 班次与时间窗口数量混淆:原始数据中班次为4个(Shift1-4),但代码用
n = a.shape[0]把时间窗口数量(8个)当成班次数量,导致决策变量y的数量错误。
修复步骤
- 提前保存薪资数据:在删除最后一行前提取薪资信息,避免丢失。
- 修正薪资数组维度:将二维数组展平为一维数组,确保索引访问正常。
- 正确定义班次数量:班次数量等于Shift列的数量(4个),而非时间窗口数量。
- 修正约束矩阵维度:约束矩阵应为
时间窗口数 × 班次数量,保证约束条件索引匹配。
修复后完整代码
import pandas as pd import pulp from pulp import LpMinimize, LpProblem, LpStatus, lpSum, LpVariable import numpy as np # 读取数据 df = pd.read_clipboard(sep='\\s+') df = pd.DataFrame(df) # 提前提取薪资数据(删除最后一行前操作) wage_row = df.iloc[-1, 1:-1].values # 提取Shift1-4的薪资,得到一维数组 # 删除薪资行,保留时间窗口数据 df = df.drop(df.tail(1).index) # 处理数据,确保班次覆盖标记为数值型 df = df.fillna(0).applymap(lambda x: 1 if x == "X" else x) # 定义关键参数 T = df.shape[0] # 时间窗口数量:8 n = len(df.columns) - 2 # 班次数量:4(排除Time Windows和Workers Required列) a = df.drop(columns=["Time Windows", "Workers Required"]).values # 约束矩阵:8×4 d = df["Workers Required"].values # 各时间段需求人数 # 决策变量:每个班次的员工数量 y = LpVariable.dicts("num_workers", list(range(n)), lowBound=0, cat="Integer") # 创建最小化问题 prob = LpProblem("scheduling_workers", LpMinimize) # 目标函数:总薪资最小化 prob += lpSum([wage_row[j] * y[j] for j in range(n)]) # 约束条件:每个时间段的在岗员工数≥需求人数 for t in range(T): prob += lpSum([a[t, j] * y[j] for j in range(n)]) >= d[t] # 求解问题 prob.solve() # 输出结果 print("求解状态:", LpStatus[prob.status]) for shift_idx in range(n): print(f"班次{shift_idx+1}需要的员工数:{int(y[shift_idx].value())}人")
说明
修复后代码正确区分了时间窗口和班次的维度,薪资数组变为一维数组,索引访问正常;约束矩阵a维度为8×4,对应8个时间窗口和4个班次,约束条件索引匹配无误。
内容的提问来源于stack exchange,提问作者ASH
相关产品推荐
相关产品推荐

