python + Pulp + gspread
シフト、スケジュール調整などを自動で行うためのスクリプトです。pythonのPulpライブラリを用いて最適化問題を解きます。 基本的にはyamlファイルの編集のみで、特定の拘束条件を加えることができるようになっています。
また、google formを利用し、回答をgoogle spreadsheetに集め、それを取得することを想定しています。 (つまり、このレポジトリにはシフトの最適化に必要なコードのみが含まれています。) このスクリプトを実行するためには、APIを利用するので、使い方の節で説明するような下準備をする必要があります。
google formに必須な調査項目は、
- 名前
- メールアドレス
- シフトの可否(チェックボックスを利用したグリッド方式)
- 入れない場合にチェックを入れてもらうことに注意
- 特筆事項を記載するコメント
となっています。 google formについてはGoogleFormの設定も参照してください。 必要な情報が記載されるシフトの列番号はsheet_structure.yamlに記入したものを読み取る設定になっているので、 項目は自由に増やしても問題ありません。(設定に関しては使い方の節で詳しく述べます。)
デフォルトでは(model.yamlに何も追記しない場合)、シフトの可否のみを考慮したテーブルが作られます。 具体的には、
- 特定のシフトには必ず一人割り当てられる
- 一つの時間スロットに同じ人が割り当てられるのを禁止する
- Formで回答されたNGのスケジュールにはシフトを入れない
の三つです。表式は、make_shifttable.pyを見てください。
また、jupyter notebookで挙動を確認したい場合は、test.ipynbを使用したり、新たにファイルを作成してください。
pythonのvenvを用いて環境を作ります。エラーが出る場合は他に何かしらインストールが必要になるかもしれません。 動作確認は以下の環境で行っています。
- Almalinux release 9.2
- python 3.9.16
- pip 23.1.2
また、仮想環境の管理にpoetry
を使用しています。
事前にpoetryのインストールをお願いします。
公式サイトで推奨されている方法は、pipx install poetry
です。
この場合はpipx
も初めにインストールしておく必要があります。
poetryがインストールできれば、まず、仮想環境の準備をしてください。 プロジェクトの中に.venvディレクトリを作成したい場合は、
poetry config virtualenvs.in-project true
というグローバルな設定を行なっておくことをお勧めします。
このリポジトリを使用するための環境は以下のようにして作成できます。
cd directory_you_want_to_install
git clone https://github.com/okawak/shift_maker.git
cd shift_maker
poetry install
初めに一度上記のコマンドを実行した後は、poetry shell
または、source .venv/bin/activate
で環境に入ることができます。
環境に入らずに実行したい場合、以下のpythonコマンドを実行する際に、poetry run
をpythonの前につけてください。
例えば、以下のようにすればpoetryで作成した環境でpythonスクリプトを実行することになります。
poetry run python script.py
pythonのパッケージであるgspreadを用いて、google spreadsheetにある情報を取得します。 gspreadを使用するためには、spreadsheetとサービスアカウントを連携させることが必要で、 その方法はgspreadの初期設定を参考にしてください。 バージョンによっては方法が変わっている場合もあるので、ご注意ください。
また初期設定時に作成される秘密鍵であるjsonファイルはjsonディレクトリの中に入れてください。 どんなファイル名でも問題ありませんが、鍵は一つだけにしてください。 (複数アカウントは対応していません。)
mv /hoge/huga.json json/
初期設定が終了したら、Input用とOutput用のスプレッドシートの構造をsheet_structure.yamlファイルに書いてください。 実際にpythonスクリプトからgoogle spreadsheetにアクセスできるかどうかをチェックしたい場合は、 chkconnect.pyを実行してください。
python chkconnection.py
successが返って来れば接続は問題ありません。
google spreadsheetから情報を取得するためには、read_data.pyを実行してください。 名前をtestにしたFormの回答を無視する、 また、同じ人が複数回答した場合は、タイムスタンプが新しいものを採用するなどの処理が行われます。 そして読み取ったデータがdata.csvに出力されます。
python read_data.py
実際にシフトを組むときには、このシフトにはこのような属性の人が必ず一人必要だといった、シフターの属性を取り入れると便利です。 シフト表の作成の項で説明するように、data.csvのattributeの列の値を用いて拘束条件を追加することができます。
何も指定がなかった場合、全員のattributeは0となるようになっていますが、 現在のバージョンでは以下のようなコマンドライン引数を設定すると、メールのドメインで属性を区別することができます。
python read_data.py -i hoge.com
これは、hoge.comのドメインを持つメールアドレスで登録されたユーザーを1の属性に、その他のユーザーを0の属性になるようにします。 コマンドライン引数で簡単に属性を追加できる条件があれば、今後アップデートをするかもしれませんが、現状は特定のドメインかどうか のみに対応していますので、ご注意ください。
したがって、複雑なattributeを指定したい場合は、直接data.csvに書き込んでください。 ここで指定された値は、モデルの設定の項で説明するように、model.yamlのattributeの値で使用します。 また、formの答え方に問題があった場合なども、このファイルを直接編集しても問題ありません。
また、formに書かれた特筆事項コメントは、まとめてcomments.txtに出力されます。
model.yamlに書かれたコメントをもとに必要な拘束条件を追記してください。 追記できる条件は、次の通りです。
- 連続のシフトを許容するかしないか
- ある特定の人が一日に最大何回までシフトの仕事をとれるか
- ある特定の人がイベント全体で最大何回までのシフトの仕事をとれるか
- ある特定の仕事には、特定のattributeの人が入らなければならない場合
- ある特定の仕事には、特定のattributeの人が入ってはいけない場合
- ある特定の時間の仕事には、特定のattributeの人が入ってはいけない場合
yamlファイルの配列を追加する形で、条件を増やすことが可能です。
また、このスクリプトで用いているモデルは、こちらを参照してください。
適切にmodel.yamlを作成したら、make_shifttable.pyを実行してシフト表を作成します。 自動でsheet_structure.yamlのOutputに書かれたシートに結果が書かれるようになっています。 結果が書かれる前に、シートをclearするので、手動で何かを加えた後にこれを実行すると、 手動で書き加えたものは消えてしまうので注意してください。
python make_shifttable.py
また、最適化することができない条件だった場合は、ターミナル上に
optimality = Infeasible, target value = 135.0
のように"Infeasible"と表示されます。 拘束条件、シフトの人数などを見直す必要があります。
うまく解を見つけられた場合、
optimality = Optimal, target value = 150.0
のように"Optimal"と表示されます。
ただし、必要な条件が足りなかったりする場合もあるので、出力されたシフトテーブルは良く確認してください。 また、comments.txtも参考にして、最終的には手動でシフトを決めた方が良い場合もあります。