Python WebフレームワークのStreamlitで機械学習アプリを作成してみた

# はじめに
お盆休みでまとまった時間があったため、今回、前々から気になっていたStreamlitというPython Webフレームワークを用いた簡易なWebアプリケーション作成にトライしてみたので記事にまとめました。百聞は一見にしかずですので最初に実際に作成した機械学習アプリのURLと動画を貼っておきます。

https://share.streamlit.io/kunishou/streamlit_tools/web_tools.py

<br>
<iframe width="560" height="400" src="https://www.youtube.com/embed/PEA1us0II4Q" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe>

# 目次
- [Streamlitとは](#Streamlitとは)
- [代表的なWebフレームワークとの比較](#代表的なWebフレームワークとの比較)
- [Streamlitでできること](#Streamlitでできること)
- [デプロイ方法](#デプロイ方法)
- [作成した機械学習アプリ](#作成した機械学習アプリ)
- [作成においてハマった点](#作成においてハマった点)
- [Streamlitを使って感じた課題](#Streamlitを使って感じた課題)
- [最後に](#最後に)

# Streamlitとは
![streamlit-logo-primary-colormark-darktext2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692165/72505546-6fc5-8ea9-f5d4-7a407a4437ea.png)

Python Webフレームワークのひとつであり、Streamlitを用いることでWeb開発で通常必要な**HTMLやCSSでのフロントエンドの記述が不要で、Pythonスクリプトのみで**良い感じのアプリを開発することが可能です。

# 代表的なWebフレームワークとの比較
PythonベースのWebフレームワークは数多くありますが、上述の通り、Pythonスクリプトのみで開発できること、また、後述しますがアプリ作成後の本番環境へのデプロイも簡易に可能なことがStreamlitのメリットになります。短所としては、細かい見た目の変更ができないことです。
<br>
私の認識では以下のような整理になります。

|Framework|概要|Python|HTML|CSS※|デプロイ|学習コスト|
|:---:|:---|:---:|:---:|:---:|:---:|:---:|
|Django|フルスタックフレームワーク、豊富な機能追加が可能、アプリ構成が複雑|〇|〇|〇|普通|高|
|Flask|マイクロフレームワーク、手軽に開発が可能|〇|〇|〇|簡易|中|
|FastAPI|マイクロフレームワーク、純正ライブラリ・ドキュメントが充実|〇|〇|〇|簡易|中|
|Streamlit|Pythonのみで開発が可能、アプリ構成がシンプル、デプロイが簡単|〇|　|　|超簡易|低|
※ 正確にはDjangoなどでもCSSの用意は必須ではないです（ないと見た目はダサくなりますが）
<br>
Djangoはユーザ認証機能、アプリの管理機能などもフレームワークに標準機能として搭載されているため、本格的なWebサービスや業務アプリケーションなどの開発をしたい場合に向いており、Streamlitはアプリのプロトタイプ開発に向いているように思います（アプリ開発初期に社内でデモを見せたいときに飛び道具的に使用するなど）。

# Streamlitでできること
* 文字の表示（Markdown記法も可能）
* データフレーム、グラフ（Plotlyにも対応）、画像の表示
* ボタン、スライダーなどのウィジェットの表示
* その他

データフレームを画面表示させる場合にHTMLの面倒な記述なしに表示できるのは非常に便利だと思いました。また、グラフ表示についてはPlotlyも対応しているのでインタラクティブなグラフの表示も可能です。

**ウィジェットを使用する場合の記述方法と表示例については以下のサンプルページにまとめましたのでご覧下さい。**

https://share.streamlit.io/kunishou/streamlit_sample/main/streamlit_sample.py

# デプロイ方法
デプロイする方法についてはStreamlit SharingというStreamlitで作成したアプリを無償でデプロイできるサービスを利用します。詳細は以下の記事にまとめられているのでご参照ください。**慣れれば5分程度でデプロイすることも可能だと思います。**

https://marutechblog.com/streamlit_sharing/?utm_source=pocket_mylist

HerokuやAWS、Azureにデプロイする方法もありますので参考記事も載せておきます。
（PythonAnywhreにデプロイしている記事は見たことがないです）。

* [Streamlitで作ったWebアプリをHerokuにデプロイする](https://qiita.com/tomowarkar/items/f41f778b6ae003d9a027)
* [StreamlitでPythonデータ分析ダッシュボードをサクッと作ってAWSにデプロイ](https://qiita.com/tkmz/items/ab0954cd9a70594bb88b)
* [Azure Web AppsとStreamlitでデータを可視化して画面を公開する](https://qiita.com/yamaskai/items/9a6178a0a21e6c89ee91)

# 作成した機械学習アプリ

https://share.streamlit.io/kunishou/streamlit_tools/web_tools.py

**ソースコード**

https://github.com/kunishou/streamlit_tools

アプリの内容ですが、PyCaretライブラリを用いた複数モデルでの予測精度比較やPandas-Profilingライブラリを用いたデータフレームのEDAなどを実施することが可能なアプリです。ただし、デプロイ先のStreamlit Sharingから割り当てられるRAMリソースの関係でPyCaretは最後までは実行ができません。

また、今回PyCaretの「compare_model()」をStreamlit上で使用していますがそのままではStreamlit上で上手く動作しなかったため、ライブラリのcompare_model関数の中身をカスタマイズしています。

# 作成においてハマった点
今回、アプリを作成するにあたりStreamlitのbutton widgetの使用における意図しない挙動の修正に時間を費やしました（2日間くらい頭を抱えました爆）。具体的には、以下の動画のような挙動です。アプリ上でbuttonを押下すると、新しいウィジェットAが出現して、ウィジェットAで次の操作を行うという作りにしていましたが、なぜかウィジェットAでの操作を終えた瞬間にbuttonの操作前の段階にページがリロードされてしまうという状況でした（動画の「Session Stateの設定なし」での挙動）。

![コンポ-5.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/692165/74a67c9c-5bbc-7022-8f5b-ab232a325357.gif)

原因としては、button widgetは押された瞬間のみTrueになりますが、その後Falseに戻るという仕様が原因でした。この仕様のため、button以降にウィジェットAで操作をした時点でbuttonはFalseに戻ります。Streamlitはコード内の変数に変化があった場合リロードされるため、今回はbuttonのところまで戻ってしまう状態でした。

対策として以下の記事の通り、StreamlitのSession State機能で変数の状態を保持することで問題を解決することができました。

https://qiita.com/kuriyan1204/items/d8342f3a40c6aeb57e5e

# Streamlitを使って感じた課題
今回、Streamlitを用いたアプリの作成から、本番環境までのデプロイを実施しました。簡易にアプリ作成ができる点は非常に便利ですが、以下の点については課題だと感じました。

* Streamlit Sharingにデプロイする場合、割り当てられるRAMリソースが少ない（1GB）。今回作成したアプリの場合、RAMが少ないため、PyCaretのような重い機械学習処理が発生するものについては本番環境では最後まで動作しない状況です（データ分析結果をグラフ表示する等、RAMをあまり消費しない用途であればまったく問題なく使えます）。
* Streamlit Sharingにデプロイする場合、ソースコードはGitHub上でパブリックにしないといけない。そのため、業務用途では使用できない。

上記の2点の課題を解決するためには、**現状ではHerokuやAWSなどにデプロイするしかないと思われます（ただし、Herokuの2.5GB RAMプランの場合、$250/月かかります）。**今後、Streamlit Sharingにも有償でRAMリソースを選択できるプランができるととても良いと思いました。

**（2021/9/21追記）**
Streamlit Sharingから有償プラン（Teams）がリリースされたようです。

https://streamlit.io/cloud

# 参考
* [pythonで簡単なWebアプリ作成：streamlitの使い方](https://kiseno-log.com/2020/07/09/python%E3%81%A7%E7%B0%A1%E5%8D%98%E3%81%AAweb%E3%82%A2%E3%83%97%E3%83%AA%E4%BD%9C%E6%88%90%EF%BC%9Astreamlit%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9/)
* [【PyCaret】ローコードで前処理からモデル作成まで](https://qiita.com/shoku-pan/items/c60e3173627591495ca4)

# 最後に
これまでDjangoやFlaskを使ったことはありましたが、Streamlitを用いれば用途は限られますがより簡易にWebアプリの作成ができると感じました。利用するにあたっても覚えなくてはいけないこともさほど多くなく数時間学習すればすぐに使えるようになるため、学習コストが低い点も魅力的です。

Pythonを触れる人でアプリ開発に興味がある人はぜひ一度使ってみて下さい。