Deep Karmaning

技術系の話から日常のことまで色々と書きます

luigiを使ってRスクリプトを実行してみる

概要

luigiという便利なバッチ実行のpythonフレームワークがあるのですが、その中でRのスクリプトを呼び出して使う例をあまり見なかったので、やってみました。

実行できる環境はdockerfile化しています。

github.com

実装

環境の準備

まずは環境の準備です。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でいい感じのスケジューラがないというときに選択肢としてはありかなと思います。

それではなにか間違い等ありましたら、ご指摘お願いいたします。

参考

R in big data pipeline – Opiate for the masses