plumberとshinyを使ってマイクロサービスを作ってみた
2018.12.5
Topics
こんにちは。データサイエンスチーム 山川です。
この記事はNHN テコラス Advent Calendar 2018の5日目の記事です。
データ分析をする際に、短時間でモデルを構築して動くモノを作りたい、ということがしばしばあります。
インフラを整備して開発環境を構築して、機能設計、開発、テスト、レビュー、デプロイ、、、と本格的なシステム開発を行うのではなく、「とりあえず」的なアウトプットがしたい場合です。
アウトプットとして要望されることが多いのが
- API
- Webアプリケーション
ですが、R言語ならいずれも簡単に提供できます。
どんなモデルを作りたいのか
まず、必要なパッケージを読み込みます。
library(tidyverse) library(plumber) library(shiny)
Rに組みこまれているcarsというデータセットがあります。
1920年代に観測されたデータで、車の速度(speed)と停止する距離(dist)を示すものです。
speedの単位はマイル/時、distの単位はフィートです。
cars %>% ggplot(aes(speed, dist)) + geom_point() + stat_smooth(method = "lm", se = FALSE, colour = "green", size = 1)
と散布図を作ると、そこそこ線形な関係がありそうです。
線形モデルを作って、
library(tidyverse) carsmodel <- lm(dist~speed, data = datasets::cars)
モデルをRda形式で保存します。
save(carsmodel, file = "carsmodel.Rda")
モデルに対してspeedを指定するとdistの推測値がかえる関数を定義します。
lmpred <- function(var){ predict(object = carsmodel, newdata = data.frame(speed = var)) %>% unname() }
lmpred関数を用いると、
lmpred(10) >[1] 21.74499
のように推測値が返ってくるわけですが、これをWebアプリケーション化やAPI化するのが、今回やりたいことです。
API化
APIと一口に言ってもさまざまですが、ここではplumberというパッケージを用いてREST APIを作ることにします。
まず、以下のコードをlmpred.Rというファイル名で保存します。
#* @get /lmpred function(speed = 1) { load("carsmodel.Rda") dist <- predict(object = carsmodel, newdata = data.frame(speed = as.numeric(speed))) %>% unname() return(dist) }
これは、
- GETメソッドに対応している
- speedのデフォルト値は1である
- 都度carsmodel.Rdaに保存されているモデルをロードしている
- distという変数を与えられたspeedの値から導出している
- distを関数の帰り値としている
といったことを意味しています。
次に以下のコードをコンソールから実行します。
rapi1 <- plumb("lmpred.R") rapi1$run(port=8000)
すると、
Starting server to listen on port 8000
Running the swagger UI at http://127.0.0.1:8000/swagger/
とメッセージが表示されます。そこで、改めてブラウザから
http://localhost:8000/lmpred?speed=10
にアクセスすると、distの推測値である21.745が返っていることが確認できます。
もちろんcurlでも確かめられて、
curl -XGET http://localhost:8000/lmpred?speed=10
を実行すると、同じ結果が得られます。
Webサービス化
次に、shinyパッケージを使ってWebサービスを作ります。
最近、RとShinyで作るWebアプリケーションという好著も出たことで、shinyは以前より使いやすくなりました。
shinyの基本的な使い方は、ユーザーインタフェースを提供するui.Rと処理系を提供するserver.Rの二つを組み合わせてWebサービスを作ることです。
まず、以下のコードをui.Rとして保存します(文字コードはUTF-8にしてください。また、うまく動かない場合は日本語をやめてメッセージを半角文字にしてみてください)。
library(shiny) shinyUI(fluidPage( sidebarLayout( sidebarPanel( numericInput("speed", h3("speedを入力してください"), value = 1)), mainPanel( h1("distの予測結果"), textOutput("text") )) ))
次に、以下のコードをserver.Rとして保存します。
library(shiny) load("carsmodel.Rda") shinyServer(function(input, output) { output$text <- renderText({ dist <- predict(object = carsmodel, newdata = data.frame(speed = input$speed)) %>% unname() return(dist) }) })
以上2ファイルをlmpredというフォルダに保存した上で、以下のコードをコンソールから実行します。
runApp("lmpred")
すると、このような画面になり、speedを入力すると、distの予測結果が表示されます。
まとめ
線形回帰モデルというあまりにも単純な例ではありましたが、ひとつのRdaファイルを用いてAPIとWebサービスの二つを作ってみました。複雑なモデルであっても、本質的には同じアプローチでサービス化ができるので、簡単なデプロイをしてみたい方はぜひ参考にしてください。
テックブログ新着情報のほか、AWSやGoogle Cloudに関するお役立ち情報を配信中!
Follow @twitterRecommends
こちらもおすすめ
-
VAEを用いたUNIXセッションのなりすまし検出
2018.12.17
-
子どもの寝かしつけが少し楽になる!スマートおばけの作り方
2018.12.3
-
エンジニアの嫁あるある
2018.12.10
Special Topics
注目記事はこちら
データ分析入門
これから始めるBigQuery基礎知識
2024.02.28
AWSの料金が 10 %割引になる!
『AWSの請求代行リセールサービス』
2024.07.16