RareJob Tech Blog

レアジョブテクノロジーズのエンジニア・デザイナーによる技術ブログです

Streamlitで時系列予測アプリを作る

こんにちは、EdTech Labの齋藤です。

レアジョブテクノロジーズ社となって四半期が経過しそうという状況です。時が経つのは早いですね。体感速度マッハ10.2です。

というわけで、今回はトップガン マーヴェリックがいかに最高の映画だったかということをお伝えしたいのですが、我慢してStreamlitを利用したWebアプリケーションを作成していきます。 ここ数ヶ月で社内の業務効率化を行うためのアプリを作成していたのですが、その際利用したものがStreamlitでとても使い勝手が良かったのでこの場を借りて紹介していこうと思います。

実際に作成した業務効率化アプリを載せるわけにはいかないので、代わりにDartsというライブラリを利用して、時系列予測ができるアプリを作っていきます。

Streamlitとは


Pythonで利用可能なフレームワークで、フロントエンドの知識の少ない人でもさくっとWebアプリを作れるサービスです。 公式サイトのWeave in interactionにもあるように、ウィジェットを追加するのもPythonのみで完結するお手軽さです。 また、公式のチートシートも充実しており、とっつきやすくなっています。

streamlit.io

Dartsとは


Pythonで利用可能なライブラリで、複数種類の時系列モデルを利用することが可能なライブラリです。 利用方法もシンプルで、ちょっと時系列モデルを試してみたいというときに非常に便利です。

unit8co.github.io

こいつらを組み合わせて、お手軽時系列予測アプリを作っていきましょう。

実装


DartsのチュートリアルをStreamlitに落とし込んでいきたいと思いますが、それだけでは寂しいので複数の時系列モデルをラジオボタンで切り替えられるものを作ろうかなと思います。 時間の都合上、利用するモデルの説明及びハイパーパラメータ の探索は省きます。

import streamlit as st

from darts import TimeSeries
from darts.models import ExponentialSmoothing, ARIMA, AutoARIMA, BATS, Theta

from sklearn.model_selection import train_test_split
import pandas as pd
import matplotlib.pyplot as plt

st.title('Dartsで時系列予測')

# Dartsの処理
# モデルの選択
model_select = st.radio(
    "使用するモデルを選んでください",
    ("ExponentialSmoothing", "ARIMA", "AutoARIMA", "BATS", "Theta"))
if model_select == "ExponentialSmoothing":
    model = ExponentialSmoothing()
    st.write("確率論的モデルです。サンプリング回数はどうしますか?")
    num_samples = st.number_input("num_samples", value=1)

elif model_select == "ARIMA":
    model = ARIMA()
    st.write("確率論的モデルです。サンプリング回数はどうしますか?")
    num_samples = st.number_input("num_samples", value=1)

elif model_select == "BATS":
    model = BATS()
    st.write("確率論的モデルです。サンプリング回数はどうしますか?")
    num_samples = st.number_input("num_samples", value=1)
# num_samplesを持たないモデル
elif model_select == "AutoARIMA":
    model = AutoARIMA()
    num_samples = 1
elif model_select == "Theta":
    model = Theta()
    num_samples = 1


# csvをアップロード
csv = st.file_uploader('Upload a CSV')

if csv is None:
    st.write("ファイルをアップロードしてください")
else:
    df = pd.read_csv(csv, delimiter=",")
    train, val = train_test_split(df, shuffle=False)
    train, val = TimeSeries.from_dataframe(train, 'Month', '#Passengers'), TimeSeries.from_dataframe(val, 'Month', '#Passengers')

    model.fit(train)
    prediction = model.predict(len(val), num_samples=num_samples)

    low_quantile = st.number_input("low_quantile", value=0.05, format="%f")
    high_quantile = st.number_input("high_quantile", value=0.95, format="%f")

    # 図の描画
    fig, axes = plt.subplots()
    series = TimeSeries.from_dataframe(df, 'Month', '#Passengers')
    series.plot()
    prediction.plot(label='forecast', low_quantile=low_quantile, high_quantile=high_quantile)
    plt.legend()
    plt.tight_layout()
    st.pyplot(fig)

できました。コーディングはこれだけです。

st.radio(("A", "B", "C"))

のようにするだけでラジオボタンが生成でき、上記のように書くことで選択された処理を行なってくれます。

Dartsの方は注意点として、データをインプットする際はfrom darts import TimeSeriesを利用する必要がありそうでした。

こいつのファイル名をstreamlit.pyとしたとき、streamlit run streamlit.pyをコマンドで実行します。 すると、8501ポートでアプリケーションサーバが起動し、Webで利用可能になります。

動作確認


というわけで、実際どんな感じかみていきましょう。

いざstreamlit run streamlit.py

fig.1
良い感じですね。

fig.2
ラジオボタンでのモデル切り替えると選択したモデルに合わせて項目が増減するのが確認できます。

サイドが寂しいな〜と思ったらst.sidebar.write('サイドバーが寂しい')のようにsidebarという一言を加えるだけで

fig.3
とサイドバーが作れます。これで寂しくないですね。ここにモデル選択用のラジオボタンを置くとかしても良いかもしれません。

データのアップロードと結果


今回はチュートリアルに沿っているので、そのままAirPassengersのデータを利用します。お馴染みですね。データのフォーマットはこんな感じです。

fig.4

画像のBrowse filesをクリックすると手持ちのファイルが選択できるのでAirPassengers.csvをアップロードしてみましょう。

fig.5

うまく予測ができていそうです。low_quantile, high_quantileを変更することで信頼区間を変えられるようにもしておきました。

上記のような簡単な実装でも、そこそこリッチなウェブアプリケーションが出来上がりました。 今回はDartsのチュートリアルをベースにしているので、AirPassengersのデータ形式のみを受け付けるようにしていますが、もちろんデータの処理を変えれば汎用的な分析・予測アプリが作れます。

アプリのデプロイ for AWS Fargate


実際に業務で作成したアプリは、実用に足るアプリにするために以下のサイトを参考にしつつ、弊社DevOpsチームから多大なご助力を得ましてAWS Fargateでデプロイしました。 towardsdatascience.com

最後に


このStreamlitを利用すれば、今回のように実際のアプリとして動かすだけではなく、分析結果の共有やインタラクティブダッシュボードの作成、プロトタイピングというように様々な場面で活用が期待できるフレームワークだなと改めて感じました。地味KPI を追ったりするのにも使えそうですね。

というわけでここまでお付き合いいただきありがとうございました!