質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

0回答

1192閲覧

データの0-1を判別する方法について。

K.takita

総合スコア14

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/12/03 05:46

前提・実現したいこと

12/2に投稿した「作成したプログラムについて」の改訂版を投稿させていただきます。
よろしくお願いします。

現在、アルバイトのシフト作成について検討しています。
作成したものが以下のプログラムです。

該当のソースコード

python

1import numpy as np 2import pandas as pd 3from pulp import LpBinary, LpMinimize, LpProblem, LpVariable, lpSum, value 4 5#アルバイトの集合 6n_member = 5 7member = pd.Series(f"member{m+1}" for m in range(n_member)) 8 9#日にちの集合 10n_day = 2 11day = pd.Series(f"day{d+1}" for d in range(n_day)) 12 13#時刻の集合 14n_time = 9 15time = pd.Series(f"{t+12}時" for t in range(n_time)) 16#t時 : t時~t+1時 17 18#シフト番号 19n_shiftnumber = 6 20shiftnumber = pd.Series(f"shift{sn+1}" for sn in range(n_shiftnumber)) 21 22#シフトの一覧 23shift = pd.read_csv('exshift.csv', header=None) 24shift.index = shiftnumber 25shift.columns = time 26 27shiftdaycount = [int(sum(x) > 0) for x in shift.values] 28 29#各シフトの労働時間 30wtime = pd.read_csv('wtime.csv', header=None) 31wtime.index = shiftnumber 32wtime.columns = day 33 34#必要人数 35need = pd.DataFrame([[2, 2, 2, 2, 2, 2, 2, 2, 2]], index=day, columns=time) 36 37#希望出勤日 38kibou = pd.DataFrame([[1, 1], 39 [1, 1], 40 [1, 1], 41 [1, 1], 42 [0, 0]], index=member, columns=day) 43 44#希望出勤時間(Day1) 45Day1kiboutime = pd.DataFrame([[0, 0, 0, 1, 1, 1, 0, 0, 0], 46 [0, 0, 0, 1, 1, 1, 0, 0, 0], 47 [1, 1, 1, 0, 0, 0, 1, 1, 1], 48 [1, 1, 1, 0, 0, 0, 1, 1, 1], 49 [0, 0, 0, 0, 0, 0, 0, 0, 0]], index=member, columns=time) 50 51#希望出勤時間(Day2) 52Day2kiboutime = pd.DataFrame([[0, 0, 0, 1, 1, 1, 0, 0, 0], 53 [0, 0, 0, 1, 1, 1, 0, 0, 0], 54 [1, 1, 1, 0, 0, 0, 1, 1, 1], 55 [1, 1, 1, 0, 0, 0, 1, 1, 1], 56 [0, 0, 0, 0, 0, 0, 0, 0, 0]], index=member, columns=time) 57 58#(Day1)希望出勤時間が0のとき、shift.values[s,t]は0 59#希望出勤時間が1のとき、制約に応じてshift[s,t]は1または0 60#となるようなシフトパターンを選択 61for m in range(member.size): 62 for t in range(time.size): 63 for s in range(n_shiftnumber): 64 if Day1kiboutime.values[m,t] == 0: 65 shift.values[s,t] == 0 66 elif Day1kiboutime.values[m,t] == 1: 67 shift.values[s,t] == 1 or 0 68 69 70#(Day2) 71for m in range(member.size): 72 for t in range(time.size): 73 for s in range(n_shiftnumber): 74 if Day2kiboutime.values[m,t] == 0: 75 shift.values[s,t] == 0 76 elif Day2kiboutime.values[m,t] == 1: 77 shift.values[s,t] == 1 or 0 78 79#各メンバーの時給 80jikyu = pd.DataFrame([[900, 900], 81 [900, 900], 82 [900, 900], 83 [900, 900], 84 [900, 900]], index=member, columns=day) 85 86#1日の人件費 87jinkenhi = pd.DataFrame([[16200], 88 [16200]], index=day) 89 90 91#モデルの作成 92prob = LpProblem(sense=LpMinimize) 93 94#変数 95X = LpVariable.dicts('X', ([m for m in range(member.size)], [d for d in range(day.size)], [s for s in range(n_shiftnumber)]), 0, 1, 'Integer') 96 97#目的関数 98prob += kibou.values.sum() - lpSum(shiftdaycount[s] * X[m][d][s] for s in range(n_shiftnumber) for d in range(day.size) for m in range(member.size)) 99 100for m in range(member.size): 101 #希望出勤日数 102 ks = kibou.iloc[m].sum() 103 #実際に働いた日数 104 actual = lpSum(shiftdaycount[s] * X[m][d][s] for s in range(n_shiftnumber) for d in range(day.size)) 105 #(制約1)実際に働いた日数が希望出勤日数を超えない制約 106 prob += actual <= ks 107 108 109#制約条件 110#(制約2)必要最低人数を満たす制約 111for d in range(day.size): 112 for t in range(time.size): 113 prob += lpSum(shift.values[s][t] * X[m][d][s] for s in range(n_shiftnumber) for m in range(member.size)) == need.iloc[d, t] 114 115#(制約4)各メンバーが1日に取りうるシフトは必ず1つ 116for m in range(member.size): 117 for d in range(day.size): 118 prob += lpSum(X[m][d][s] for s in range(n_shiftnumber)) == 1 119 120#(制約5)人件費を超えない 121for s in range(n_shiftnumber): 122 for d in range(day.size): 123 prob += lpSum(jikyu.iloc[m, d] * wtime.iloc[s, d] * X[m][d][s] for m in range(member.size)) <= jinkenhi.iloc[d] 124 125#(制約6)6日以上の連続勤務を禁止する 126for m in range(member.size): 127 prob += lpSum(X[m][d] for d in range(day.size)) <= 6 128 129prob.solve() 130 131 132scheduling = pd.DataFrame(index=member, columns=day) 133for m in range(member.size): 134 for d in range(day.size): 135 for s in range(n_shiftnumber): 136 if X[m][d][s].value() == 1: 137 scheduling.iloc[m, d] = shiftnumber[s] 138 139scheduling.to_csv("scheduling.csv") 140 141

###各csvファイルの内容

#シフトの一覧 shift 12時 13時 14時 15時 16時 17時 18時 19時 20時 shift1 0 0 0 0 0 0 0 0 0 shift2 1 1 1 1 1 1 1 1 1 shift3 1 1 1 0 0 0 0 0 0 shift4 0 0 0 1 1 1 0 0 0 shift5 0 0 0 0 0 0 1 1 1 shift6 1 1 1 0 0 0 1 1 1 #各シフトの労働時間 wtime day1 day2 shift1 0 0 shift2 9 9 shift3 3 3 shift4 3 3 shift5 3 3 shift6 6 6

上記のプログラムの希望出勤時間についてですが、日ごとの出勤可能な時間を1で、出勤不可の時間を0で表しています。
しかしそのままでは希望出勤時間が0でも1でも関係なくプログラムが動いてしまうため、#(Day1)と#(Day2)部分を追加しました。内容としては希望出勤時間が0のところはshiftが0になり、希望出勤時間が1のところは、制約に応じて0または1を選択し、その文字列をもとに各メンバーのシフトが決定するというものです。
今回のプログラムでは、下記に記載した理想の結果のようになれば良いのですが、実際の結果違いました。
###理想の結果

day1 day2 member1 shift4 shift4 member2 shift4 shift4 member3 shift6 shift6 member4 shift6 shift6 member5 shift1 shift1

###実際の結果

day1 day2 member1 shift4 shift4 member2 shift6 shift3 member3 shift6 shift5 member4 shift4 shift2 member5 shift1 shift1

必要人数や人件費に関する制約などは満たしているため、制約部分に間違いはないのだと思います。
希望出勤時間の0-1を判別し、希望出勤時間が1の中で最適なシフトを割り当てるにはどこをどのように変更すればいいか教えていただきたいと思い質問させていただきます。
お手数ですがよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hentaiman

2020/12/03 06:42

read_csvのところを用意するのが面倒なのでその部分のデータ直書きしてコピペで現状の動作確認出来るようにしてみてくだされ
K.takita

2020/12/03 12:00

返信遅くなってしまい申し訳ありません。 以下がデータを直書きしたものです。よろしくお願いします。 #シフトの一覧 shift = pd.DataFrame([[0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 0, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 1, 1, 1], [1, 1, 1, 0, 0, 0, 1, 1, 1]], index=shiftnumber, columns=time) #各シフトの労働時間 wtime = pd.DataFrame([[0, 0], [9, 9], [3, 3], [3, 3], [3, 3], [6, 6]], index=shiftnumber, columns=day)
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問