Trying to Optimize Process Using Linear Programming. Getting error about: IndexError: index 1 is out of bounds for axis 0 with size 1

huangapple go评论68阅读模式
英文:

Trying to Optimize Process Using Linear Programming. Getting error about: IndexError: index 1 is out of bounds for axis 0 with size 1

问题

在这行代码中:

prob += lpSum([w[j] * y[j] for j in range(n)])

你遇到了这个错误:

IndexError: index 1 is out of bounds for axis 0 with size 1

这个错误是因为在 w 中的数据是一个一维数组,但你尝试访问索引1,而实际上只有一个元素,索引应为0。你可以尝试将 w 定义为一个标量值而不是一个数组,或者根据你的需求调整代码来解决这个错误。

英文:

I am trying to optimize worker's schedules, based on the following dataframe.

    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

First (create dataframe):

import pandas as pd
df = pd.read_clipboard(sep='\\s+')
df = pd.DataFrame(df)

Here is the code that I am testing.

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


df = df.fillna(0).applymap(lambda x: 1 if x == "X" else x)

df.set_index('Time Windows')
a = df.drop(columns=["Workers Required"]).values
a


df.drop(df.tail(1).index,inplace=True)
print(df.shape)


df = df.fillna(0).applymap(lambda x: 1 if x == "X" else x)
print(df.shape)


a = df.to_numpy()
a


# number of shifts
n = a.shape[0]


# number of time windows
T = a.shape[0]


# number of workers required per time window
d = df["Workers Required"].values


# wage rate per shift
#Get last row of dataframe
last_row = df.iloc[-1:,1:]
#Get last row of dataframe as numpy array
w = last_row.to_numpy()
w


# Decision variables
y = LpVariable.dicts("num_workers", list(range(n)), lowBound=0, cat="Integer")
y


# Create problem
prob = LpProblem("scheduling_workers", LpMinimize)



prob += lpSum([w[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("Status:", LpStatus[prob.status])


for shift in range(n):
    print(f"The number of workers needed for shift {shift} is {int(y[shift].value())} workers")

When I get to this line:

prob += lpSum([w[j] * y[j] for j in range(n)])

I get this error.

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

The example I am trying to follow is from the link below.

https://towardsdatascience.com/how-to-solve-a-staff-scheduling-problem-with-python-63ae50435ba4

答案1

得分: 1

你的问题主要是因为对 Pandas 的误用。正确使用切片,它将正常工作:

from io import StringIO
import pandas as pd
import pulp

with StringIO(
    '''Time Windows,Shift 1,Shift 2,Shift 3,Shift 4,Workers Required
    6:00 - 9:00,      1,      0,      0,      1,            55.0
   9:00 - 12:00,      1,      0,      0,      0,            46.0
  12:00 - 15:00,      1,      1,      0,      0,            59.0
  15:00 - 18:00,      0,      1,      0,      0,            23.0
  18:00 - 21:00,      0,      1,      1,      0,            60.0
  21:00 - 24:00,      0,      0,      1,      0,            38.0
   24:00 - 3:00,      0,      0,      1,      1,            20.0
    3:00 - 6:00,      0,      0,      0,      1,            30.0
      Wage_Rate,    135,    140,    190,    188,             0.0''') as f:
    df = pd.read_csv(f, skipinitialspace=True, index_col='Time Windows')

is_shift = df.columns.str.startswith('Shift')
is_wage = df.index == 'Wage_Rate'
shifts = df.loc[~is_wage, is_shift]
wage_rate = df.loc[is_wage, is_shift].squeeze()
workers_req = df.loc[~is_wage, 'Workers Required']

workers_per_shift = pulp.LpVariable.dicts(name='workers_per', indices=shifts.columns, lowBound=0, cat=pulp.LpInteger)
prob = pulp.LpProblem(name='scheduling_workers', sense=pulp.LpMinimize)
prob.objective = pulp.lpDot(wage_rate, workers_per_shift.values())

for (time, shift), worker_req in zip(shifts.iterrows(), workers_req):
    prob.addConstraint(name=f'workers_min_{time}', constraint=pulp.lpDot(shift, workers_per_shift.values()) >= worker_req)

print(prob)
prob.solve()

for k, v in workers_per_shift.items():
    print(f'{k} has {v.value():.0f} workers')
scheduling_workers:
MINIMIZE
135*workers_per_Shift_1 + 140*workers_per_Shift_2 + 190*workers_per_Shift_3 + 188*workers_per_Shift_4 + 0
SUBJECT TO
workers_min_6:00___9:00: workers_per_Shift_1 + workers_per_Shift_4 >= 55

workers_min_9:00___12:00: workers_per_Shift_1 >= 46

workers_min_12:00___15:00: workers_per_Shift_1 + workers_per_Shift_2 >= 59

workers_min_15:00___18:00: workers_per_Shift_2 >= 23

workers_min_18:00___21:00: workers_per_Shift_2 + workers_per_Shift_3 >= 60

workers_min_21:00___24:00: workers_per_Shift_3 >= 38

workers_min_24:00___3:00: workers_per_Shift_3 + workers_per_Shift_4 >= 20

workers_min_3:00___6:00: workers_per_Shift_4 >= 30

VARIABLES
0 <= workers_per_Shift_1 Integer
0 <= workers_per_Shift_2 Integer
0 <= workers_per_Shift_3 Integer
0 <= workers_per_Shift_4 Integer

欢迎使用 CBC MILP 求解器
版本:2.10.3
构建日期:2019年12月15日

命令行 - C:\Users\gtoom\src\stackexchange\.venv\lib\site-packages\pulp\solverdir\cbc\win\cbc.exe C:\Users\gtoom\AppData\Local\Temp759563a6c3439b8221b857b9f617af-pulp.mps timeMode elapsed branch printingOptions all solution C:\Users\gtoom\AppData\Local\Temp759563a6c3439b8221b857b9f617af-pulp.sol (默认策略 1)
第2行 NAME          MODEL
第3行 ROWS
第13行 COLUMNS
第38行 RHS
第47行 BOUNDS
第52行 ENDATA
问题 MODEL 共有 8 行,4 列,12 个元素
Coin0008I 以 0 个错误读取模型
将 timeMode 选项从 CPU 更改为经过的时间
连续目标值为 22290 - 0.00 秒
Cgl0004I 处理后的模型有 0 行,0 列(0 个整数(其中 0 个是二进制))和 0 个元素
Cbc3007W 没有整数变量 - 无事可做
根节点处的切割将目标从 22290 更改为 -1.79769e+308
探测尝试了 0 次,并在添加切割回合后创建了 0 个切割,其中 0 个活跃(0.000 秒)
Gomory 尝试了 0 次,并在添加切割回合后创建了 0 个切割,其中 0 个活跃(0.000 秒)
尝试了 0 次的背包问题,并创建了 0 个切割,其中 0 个在添加切割回合后是活跃的(0.000 秒)
尝试了 0 次的团问题,并创建了 0 个切割,其中 0 个在添加切割回合后是活跃的(0.000 秒)
尝试了 0 次的混合整数舍入问题,并创建了 0 个切割,其中 0 个在添加切割回合后是活跃的(0.000 秒)
FlowCover 尝试了 0 次,并创建了 0 

<details>
<summary>英文:</summary>

Your problems mostly come from misuse of Pandas. Use sane slicing, and it works fine:

```python
from io import StringIO

import pandas as pd
import pulp

with StringIO(
&#39;&#39;&#39;Time Windows,Shift 1,Shift 2,Shift 3,Shift 4,Workers Required
    6:00 - 9:00,      1,      0,      0,      1,            55.0
   9:00 - 12:00,      1,      0,      0,      0,            46.0
  12:00 - 15:00,      1,      1,      0,      0,            59.0
  15:00 - 18:00,      0,      1,      0,      0,            23.0
  18:00 - 21:00,      0,      1,      1,      0,            60.0
  21:00 - 24:00,      0,      0,      1,      0,            38.0
   24:00 - 3:00,      0,      0,      1,      1,            20.0
    3:00 - 6:00,      0,      0,      0,      1,            30.0
      Wage_Rate,    135,    140,    190,    188,             0.0&#39;&#39;&#39;) as f:
    df = pd.read_csv(f, skipinitialspace=True, index_col=&#39;Time Windows&#39;)

is_shift = df.columns.str.startswith(&#39;Shift&#39;)
is_wage = df.index == &#39;Wage_Rate&#39;
shifts = df.loc[~is_wage, is_shift]
wage_rate = df.loc[is_wage, is_shift].squeeze()
workers_req = df.loc[~is_wage, &#39;Workers Required&#39;]

workers_per_shift = pulp.LpVariable.dicts(name=&#39;workers_per&#39;, indices=shifts.columns, lowBound=0, cat=pulp.LpInteger)
prob = pulp.LpProblem(name=&#39;scheduling_workers&#39;, sense=pulp.LpMinimize)
prob.objective = pulp.lpDot(wage_rate, workers_per_shift.values())

for (time, shift), worker_req in zip(shifts.iterrows(), workers_req):
    prob.addConstraint(name=f&#39;workers_min_{time}&#39;, constraint=pulp.lpDot(shift, workers_per_shift.values()) &gt;= worker_req)

print(prob)
prob.solve()

for k, v in workers_per_shift.items():
    print(f&#39;{k} has {v.value():.0f} workers&#39;)
scheduling_workers:
MINIMIZE
135*workers_per_Shift_1 + 140*workers_per_Shift_2 + 190*workers_per_Shift_3 + 188*workers_per_Shift_4 + 0
SUBJECT TO
workers_min_6:00___9:00: workers_per_Shift_1 + workers_per_Shift_4 &gt;= 55

workers_min_9:00___12:00: workers_per_Shift_1 &gt;= 46

workers_min_12:00___15:00: workers_per_Shift_1 + workers_per_Shift_2 &gt;= 59

workers_min_15:00___18:00: workers_per_Shift_2 &gt;= 23

workers_min_18:00___21:00: workers_per_Shift_2 + workers_per_Shift_3 &gt;= 60

workers_min_21:00___24:00: workers_per_Shift_3 &gt;= 38

workers_min_24:00___3:00: workers_per_Shift_3 + workers_per_Shift_4 &gt;= 20

workers_min_3:00___6:00: workers_per_Shift_4 &gt;= 30

VARIABLES
0 &lt;= workers_per_Shift_1 Integer
0 &lt;= workers_per_Shift_2 Integer
0 &lt;= workers_per_Shift_3 Integer
0 &lt;= workers_per_Shift_4 Integer

Welcome to the CBC MILP Solver 
Version: 2.10.3 
Build Date: Dec 15 2019 

command line - C:\Users\gtoom\src\stackexchange\.venv\lib\site-packages\pulp\solverdir\cbc\win\cbc.exe C:\Users\gtoom\AppData\Local\Temp759563a6c3439b8221b857b9f617af-pulp.mps timeMode elapsed branch printingOptions all solution C:\Users\gtoom\AppData\Local\Temp759563a6c3439b8221b857b9f617af-pulp.sol (default strategy 1)
At line 2 NAME          MODEL
At line 3 ROWS
At line 13 COLUMNS
At line 38 RHS
At line 47 BOUNDS
At line 52 ENDATA
Problem MODEL has 8 rows, 4 columns and 12 elements
Coin0008I MODEL read with 0 errors
Option for timeMode changed from cpu to elapsed
Continuous objective value is 22290 - 0.00 seconds
Cgl0004I processed model has 0 rows, 0 columns (0 integer (0 of which binary)) and 0 elements
Cbc3007W No integer variables - nothing to do
Cuts at root node changed objective from 22290 to -1.79769e+308
Probing was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Gomory was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Knapsack was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
Clique was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
MixedIntegerRounding2 was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
FlowCover was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
TwoMirCuts was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)
ZeroHalf was tried 0 times and created 0 cuts of which 0 were active after adding rounds of cuts (0.000 seconds)

Result - Optimal solution found

Objective value:                22290.00000000
Enumerated nodes:               0
Total iterations:               0
Time (CPU seconds):             0.00
Time (Wallclock seconds):       0.00

Option for printingOptions changed from normal to all
Total time (CPU seconds):       0.01   (Wallclock seconds):       0.01

Shift 1 has 46 workers
Shift 2 has 23 workers
Shift 3 has 38 workers
Shift 4 has 30 workers

huangapple
  • 本文由 发表于 2023年4月4日 07:54:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/75924536.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定