luigiを使ってRスクリプトを実行してみる
概要
luigiという便利なバッチ実行のpythonフレームワークがあるのですが、その中でRのスクリプトを呼び出して使う例をあまり見なかったので、やってみました。
実行できる環境はdockerfile化しています。
実装
環境の準備
まずは環境の準備です。dockerfileは以下のように準備します。
FROM ubuntu:18.04 #set up timezone #https://sleepless-se.net/2018/07/31/docker-build-tzdata-ubuntu/ RUN DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y tzdata # timezone setting ENV TZ=Asia/Tokyo #print command RUN set -x #install R RUN apt-get update && \ apt-get install -y --no-install-recommends sudo ed clang ccache software-properties-common dirmngr gpg-agent gdebi-core RUN sudo apt-get update && \ gpg --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E298A3A825C0D65DFD57CBB651716619E084DAB9 && \ gpg -a --export E298A3A825C0D65DFD57CBB651716619E084DAB9 | sudo apt-key add - && \ sudo add-apt-repository 'deb https://cloud.r-project.org/bin/linux/ubuntu bionic-cran35/' && \ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys E084DAB9 && \ sudo apt-get update && \ sudo apt-get install -y r-base #install luigi RUN sudo apt install -y python-pip python3-pip &&\ pip3 install luigi RUN mkdir /home/examples COPY examples/ /home/examples
ubuntu18.04のイメージをベースにR、Pythonを入れてluigiパッケージをpipコマンドで入れています。
これでビルドすればpythonとRが動く環境でluigiがインストールできましたので、あとはluigiからRスクリプトを呼び出せればOKです。
タスクの処理の実装
Pythonでタスクの処理を実装します(main.py)。今回は2つのタスクを実装し、それぞれRtask1、Rtask2としました。
import luigi import os class Rtask1(luigi.Task): def requires(self): pass def output(self): return luigi.LocalTarget('home/examples/sample1/output/hello_world1.csv') def run(self): os.system("/usr/bin/Rscript home/examples/sample1/tasks/r1.R") class Rtask2(luigi.Task): def requires(self): return Rtask1() def output(self): return luigi.LocalTarget('home/examples/sample1/output/hello_world2.csv') def run(self): os.system("/usr/bin/Rscript home/examples/sample1/tasks/r2.R") if __name__ == '__main__': luigi.run(['Rtask2', '--local-scheduler'])
Rtaks2はRtask1に依存しており、Rtask1はr1.Rを実行しRtask2はr2.Rを実行するというタスクになっています。
具体的な処理の実装
今回のタスクはRのスクリプトを呼び出すものになっています。
r1.Rとr2.Rはほぼ同じタスクなので、r1.Rだけ説明します。
print("r1") x <- data.frame(x = 1, y = 2) write.csv(x, "home/examples/sample1/output/hello_world1.csv")
やっていることは適当なデータフレームを作ってそれを出力するだけです。
4行目の出力がタスク処理のpythonスクリプトのluigi.LocalTarget('home/examples/sample1/output/hello_world1.csv')
と一致させることで、outputが適切にされたかどうかを判定しています。
r2.Rは1行目のprintの内容と、最後の出力先が異なるだけです。
タスク実行
ではタスクを実行してみましょう。
python main.py
とすると、
===== Luigi Execution Summary ===== Scheduled 2 tasks of which: * 2 ran successfully: - 1 Rtask1() - 1 Rtask2() This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====
というような結果が返ってきます。2 ran successfully
となっているのでうまく行っているようですね。
もう一度実行してみると、
===== Luigi Execution Summary ===== Scheduled 1 tasks of which: * 1 complete ones were encountered: - 1 Rtask2() Did not run any tasks This progress looks :) because there were no failed tasks or missing dependencies ===== Luigi Execution Summary =====
Did not run any tasks
となって、特に何も実行されていないことがわかります。すでに結果があるので実行されていないようです。
まとめ
今回はpythonの便利なタスク実行フレームワークであるluigiでRのスクリプトを動かしてみました。個人的にはとても簡単にやりたいことができるという感触です。
Rで統計処理を行う処理を定期実行したい時があって、単純なcronだと不十分、Rでいい感じのスケジューラがないというときに選択肢としてはありかなと思います。
それではなにか間違い等ありましたら、ご指摘お願いいたします。