Pythonシフトスケジューリングの最適化

user3833942

私は現在、仕事のためのシフトスケジューリングアルゴリズムに取り組んでいます。私たちのシフトスケジュールは完全に4-3(4日オン、3日オフ)と4-3のローテーション(例:日曜日、月曜日、火曜日、1週間と翌週オフ、日曜日、金曜日、土曜日オフ)で構成されています)-日曜日から土曜日までの週。

「ストレート」4-3シフトまたは回転4-3のいずれかの49の可能なバリエーションがあります。24時間年中無休の運用であるため、7日間すべてを考慮する必要があります。現在、これをアーリーシフトで11人、レイトシフトで12人の小規模なワークグループに利用していますが、このアルゴリズムを拡張したい200人ものワークグループが他にもあります。

基本的な前提は、管理グループには毎日必要な人員があり、アルゴリズムは必要な人員を与える初期シフトと後期シフトのセットのみを返すことです。

11人に49の可能なシフトを(繰り返しで)配置し、それらすべての可能な組み合わせを分類するのに数千年かかることが非常に早く明らかになりました。その結果、49シフトのリストを、最も一般的に使用されるシフトの約16〜20に選別することができました。

それはそれを扱いやすくしますが、11人か12人だけです。明らかに、可能な組み合わせの数は、人が追加されるたびに指数関数的に増加します。現在のところ、私のアルゴリズムは次のことを行います。

  1. 私は変数として、2週間にわたって、そこにある曜日ごとに「オンシフト」と「オフシフト」を表す1と0のシフトの束を持っています。今のところサンプルのみを使用します。例:

    h = [0,1,1,1,1,0,0,0,1,1,1,1,0,0]
    e = [0,0,1,1,1,1,0,0,0,1,1,1,1,0]
    d = [0,0,0,1,1,1,1,0,0,0,1,1,1,1]
    c = [1,1,1,1,0,0,0,1,1,1,1,0,0,0]
    m = [0,1,1,0,1,1,0,0,1,1,0,1,1,0]
    p = [1,1,0,0,0,1,1,1,1,0,0,0,1,1]
    q1 = [1,1,1,0,0,0,1,1,1,1,0,0,0,1]
    a = [1,0,0,0,1,1,1,1,0,0,0,1,1,1]
    

次に、約16〜20(この例では8のみを使用します)シフトのリストがあります。これは、排他的ではないにしても、最も一般的に使用されます。さらに、計算する人数の変数と、マネージャーの要件の変数(early_count):

shifts = [h,e,c,d,m,p,q1, a]
early_bid_personnel = 11
early_count = [5,6,7,7,6,8,5]

次に、ジェネレータ式でアーリーシフトの可能なすべてのシフトの組み合わせを作成し、日曜日が必要な数(5)になるかどうかを確認します。日曜日に合計されるものは、monジェネレーター式によって参照され、それらすべての月曜日は表にされてから、火曜日リストによって参照されます。私はこれを14日間にわたって行います。これは、交代制勤務によって2週目の人員のバランスが歪むためです。

sun = (combs for combs in combinations_with_replacement(shifts,early_bid_personnel) if (sum(combs[i][0] for i in range(0,early_bid_personnel)) == early_count[0]))
mon = (mon for mon in sun if (sum(mon[i][1] for i in range(0,early_bid_personnel)) == early_count[1]))
tue = (tue for tue in mon if (sum(tue[i][2] for i in range(0,early_bid_personnel)) == early_count[2]))
wed = (wed for wed in tue if (sum(wed[i][3] for i in range(0,early_bid_personnel)) == early_count[3]))
thu = (thu for thu in wed if (sum(thu[i][4] for i in range(0,early_bid_personnel)) == early_count[4]))
fri = (fri for fri in thu if (sum(fri[i][5] for i in range(0,early_bid_personnel)) == early_count[5]))
sat = (sat for sat in fri if (sum(sat[i][6] for i in range(0,early_bid_personnel)) == early_count[6]))
sec_sun = (sec_sun for sec_sun in sat if (sum(sec_sun[i][7] for i in range(0,early_bid_personnel)) == early_count[0]))
sec_mon = (sec_mon for sec_mon in sec_sun if (sum(sec_mon[i][8] for i in range(0,early_bid_personnel)) == early_count[1]))
sec_tue = (sec_tue for sec_tue in sec_mon if (sum(sec_tue[i][9] for i in range(0,early_bid_personnel)) == early_count[2]))
sec_wed = (sec_wed for sec_wed in sec_tue if (sum(sec_wed[i][10] for i in range(0,early_bid_personnel)) == early_count[3]))
sec_thu = (sec_thu for sec_thu in sec_wed if (sum(sec_thu[i][11] for i in range(0,early_bid_personnel)) == early_count[4]))
sec_fri = (sec_fri for sec_fri in sec_thu if (sum(sec_fri[i][12] for i in range(0,early_bid_personnel)) == early_count[5]))
sec_sat = (sec_sat for sec_sat in sec_fri if (sum(sec_sat[i][13] for i in range(0,early_bid_personnel)) == early_count[6]))

繰り返し処理するsec_sat式は、カスタム辞書で1と0の文字列を検索し、それをシフト割り当ての実際の文字に変換します。それから私は基本的に遅いシフトのためにまったく同じことを繰り返します。この2つを組み合わせると、マネージャーは探している正確な数を知ることができます。これは問題なく機能します。たとえば、8シフトしかない11人が早い段階から選択し、12人が8シフト遅れて選択します。しかし、ワークグループのサイズがたとえば20人に拡大し、12、14、16を使用するか、49シフトすべてをあえぎながらシフトを決定したい場合、それでもかなり不合理です。

私は、最初のジェネレータ式がまだ各組み合わせを置換でチェックし、日曜日が合計されたものだけを返すことを理解しています。それが主要な問題です。これをO(n ^ 2)よりも良くしたり、悪くしたりする方法を見つけるために、私は真剣にいくつかの助けを使うことができました。

考えられるすべての組み合わせを生成し、それぞれをチェックする方法はありますか?また、最大5'a 'シフトなど、最初のジェネレータ式にいくつかの制約を設定すると、次のようになります。

sun = (combs for combs in combinations_with_replacement(shifts,early_bid_personnel) if (sum(combs[i][0] for i in range(0,early_bid_personnel)) == early_count[0]) and combs.count(a) <= 5)

ジェネレータ式はまだ何かを生成する必要があります。5つ以下の「a」シフトがあるかどうかを確認し、それ以上ある場合はスキップします。

ホセ・ヴァレス

この問題を解決するには、モンテカルロシミュレーションを使用できます。可能なすべての組み合わせを実行する必要はありません。基準を満たすものを見つける必要があるだけで、たくさんあります。あなたの問題を再定義させてください。する[日、月、火曜、...、sec_sat]上司の要件。[q1、q2、...、q49]は、49の異なるシフトのそれぞれの人数になります。そしてマトリックス:

s1[0]  s1[1] ... s1[13]
s2[0]  s2[1] ... s2[13]
....................
s49[0] s49[1] ... s49[13]

は、すべてのシフトおよび曜日のオン/オフテーブルです。例:日曜日がシフト1の当日である場合、s1 [0]は1になり、それ以外の場合は0になります。s3 [7]は、第2日曜日がシフト3の当日である場合は1、それ以外の場合は0になります。などなど。この定義を使用すると、問題を次のように書き直すことができます。

sun       <=  q1*s1[0] + ... +  q49*s49[0]
mon       <=  q1*s1[1] + ... + q49*s49[1]
tue       <=  q1*s1[2] + ... + q49*s49[2]
wed       <=  q1*s1[3] + ... + q49*s49[3]
thu       <=  q1*s1[4] + ... + q49*s49[4]
fri       <=  q1*s1[5] + ... + q49*s49[5]
sat       <=  q1*s1[6] + ... + q49*s49[6]
sec_sun   <=  q1*s1[7] + ... + q49*s49[7]
sec_mon   <=  q1*s1[8] + ... + q49*s49[8]
sec_tue   <=  q1*s1[9] + ... + q49*s49[9]
sec_wed   <=  q1*s1[10] + ... + q49*s49[10]
sec_thu   <=  q1*s1[11] + ... + q49*s49[11]
sec_fri   <=  q1*s1[12] + ... + q49*s49[12]
sec_sat   <=  q1*s1[13] + ... + q49*s49[13]

あなたの未知数は[q1、q2、...、q49]です。残りは知られています。シミュレーションを使用して解決策を見つける方法は?ランダムな[q1、...、q49]ベクトルを生成し、基準が満たされているかどうかを確認します。そうである場合は、アルゴリズムを破って結果を返します。例(一種の擬似コード):

import random
# Define your restrictions
mon = 
tue = 
.........
sec_sat = 
# Define your shifts
s1 = [1,1,1,1,0,0,0,1,1,1,1,0,0,0]
s2 = [0,1,1,1,1,0,0,0,1,1,1,1,0,0]
...................................
s49 = [...]
while True:
    q = [0]*49
    # We place workers in random shifts
    for i in range(number_of_workers):
        q[random.randint(0,len(q)-1)] += 1

    if (mon <= q[0]*s1[0] + q[1]*s2[0] + ... + q[48]*s49[0]) and
       (tue <= q[0]*s1[1] + q[1]*s2[1] + ... + q[48]*s49[1]) and         
       .........................................................
       (sec_sat <= q[0]*s1[13] + q[1]*s2[13] + ... + q[48]*s49[13]):
       # Condition met, return result
       return q

上記の例のソリューションを、シフト数を制限して実装しました。

import random
# Restrictions
r = [5, 6, 7, 7, 6, 8, 5, 5, 6, 7, 7, 6, 8, 5]
# Shifts
s = []
s.append([0,1,1,1,1,0,0,0,1,1,1,1,0,0])
s.append([0,0,1,1,1,1,0,0,0,1,1,1,1,0])
s.append([0,0,0,1,1,1,1,0,0,0,1,1,1,1])
s.append([1,1,1,1,0,0,0,1,1,1,1,0,0,0])
s.append([0,1,1,0,1,1,0,0,1,1,0,1,1,0])
s.append([1,1,0,0,0,1,1,1,1,0,0,0,1,1])
s.append([1,1,1,0,0,0,1,1,1,1,0,0,0,1])
s.append([1,0,0,0,1,1,1,1,0,0,0,1,1,1])

number_of_shifts = len(s)
number_of_workers = 11
number_of_days = len(s[0])

while True:
    q = [0]*number_of_shifts
    for i in range(number_of_workers):
        q[random.randint(0,len(q)-1)] += 1
    t = [sum([q[j]*s[j][i] for j in range(number_of_shifts)]) for i in range(number_of_days)]
    if sum([r[i] <= t[i] for i in range(number_of_days)]) == number_of_days:
        print q
        break

実行するのにそれほど時間はかかりませんでした。これはそれが見つけた解決策の1つです:[0、3、2、2、1、2、1、0]

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

ファイルの行数の最適化(最小化):順列とアジェンダスケジューリングに沿った最適化問題

ハロゲン化物の最適なスケジューリング

PLSQL スクリプトの最適化/チューニング

optaplannerスケジューリングAIは、大学のスケジュールを最適化するのに適していますか?

OpenMPはforループのスケジューリングを最適化します

3列のロジックパズル:リスト/配列のシーケンス制約の最適化

タイムスロットの数を最小限に抑えるためのスケジューリングの最適化(制約付き)

Rでの最適化:バイナリスケジューリング変数を使用したコスト関数?

素数シーケンスの最適化

ビューポートに最適な画像のスケーリング

月光-最適なスケジューリングの実行不可能なソリューション、グロビとの比較

ジュリア:単純な動的システムのシミュレーションを最適化する

リリース前のAndroidアプリケーションの最適化

スケジューリングの制約と最適化を伴うハッカソンチームの割り当て

グリッドの最適化とスケーリングの問題

C ++コードの次のフラグメントを最適化する方法-ボリューム内のゼロクロッシング

java.io パッケージのバッファリングがパフォーマンスを最適化する方法

.NET A *パスファインディングの最適化、シリアル化?

Python不和ボットのスケジューリング

多くのファイルでのPython関数呼び出しの並列化/スケジューリング

リストを含むオブジェクトのフィルタリングを最適化する方法は?

1日あたりのシフト数と看護師の可用性を変化させた看護師のスケジューリング

K8sポッドの最適なスケジューリング戦略は何ですか?

3シフトの従業員スケジューリング24/7パターン

.NETPOCOのJSONシリアル化パフォーマンスの最適化

Pythonでしきい値の長さ未満のサブリストをグループ化する関数に対するエレガントで最適化されたソリューション

スケーリングを必要とする放物面の最適化

Webアプリケーション用の画像の最適化

AzureでのPythonスクリプトのスケジューリング

TOP 一覧

  1. 1

    Unity:未知のスクリプトをGameObject(カスタムエディター)に動的にアタッチする方法

  2. 2

    セレンのモデルダイアログからテキストを抽出するにはどうすればよいですか?

  3. 3

    Ansibleで複数行のシェルスクリプトを実行する方法

  4. 4

    tkinterウィンドウを閉じてもPythonプログラムが終了しない

  5. 5

    Crashlytics:コンパイラー生成とはどういう意味ですか?

  6. 6

    GoDaddyでのCKEditorとKCfinderの画像プレビュー

  7. 7

    Windows 10 Pro 1709を1803、1809、または1903に更新しますか?

  8. 8

    Chromeウェブアプリのウェブビューの高さの問題

  9. 9

    モーダルダイアログを自動的に閉じる-サーバーコードが完了したら、Googleスプレッドシートのダイアログを閉じます

  10. 10

    Windows 10の起動時間:以前は20秒でしたが、現在は6〜8倍になっています

  11. 11

    Reactでclsxを使用する方法

  12. 12

    ファイル内の2つのマーカー間のテキストを、別のファイルのテキストのセクションに置き換えるにはどうすればよいですか?

  13. 13

    MLでのデータ前処理の背後にある直感

  14. 14

    グラフからテーブルに条件付き書式を適用するにはどうすればよいですか?

  15. 15

    Pythonを使用して同じ列の同じ値の間の時差を取得する方法

  16. 16

    mutate_allとifelseを組み合わせるにはどうすればよいですか

  17. 17

    ネットワークグラフで、ネットワークコンポーネントにカーソルを合わせたときに、それらを強調表示するにはどうすればよいですか?

  18. 18

    テキストフィールドの値に基づいて UIslider を移動します

  19. 19

    BLOBストレージからデータを読み取り、Azure関数アプリを使用してデータにアクセスする方法

  20. 20

    PowerShellの分割ファイルへのヘッダーの追加

  21. 21

    ソートされた検索、ターゲット値未満の数をカウント

ホットタグ

アーカイブ