340
325

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Streamlit入門+応用 ~ データ分析Webアプリを爆速で開発する

Last updated at Posted at 2022-07-14

はじめに

この記事では、Streamlitの概要を説明し、Streamlitを使ってデータ分析Webアプリを実際に開発する中でStreamlitの機能をいろいろと紹介していきます。最終的に以下のようなApacheやTomcatなどのアクセスログを解析するWebアプリをつくります。

strmlt.gif

Streamlitとは

Streamlitは、Pythonで実装されたオープンソースのWebアプリケーションのフレームワークであり、機械学習やデータサイエンス向けのグラフィカルなWebアプリを簡単に作成して全世界に公開(クラウドサービスにデプロイ)できます。

主な特徴

  • Pythonのみで実装可能(HTMLやCSS、JavaScriptなどフロントエンドのコードを書かなくていい)
  • 豊富なウィジェットが利用可能
  • Google ColabやJupyter Notebookで作成したPythonのコードがほぼそのまま利用できる
  • 開発したアプリをStreamlit Cloudで全世界に簡単に公開可能
  • コードの修正が即座に反映され、確認できる

どのようなものがつくれるのか

Streamlitの公式サイトのギャラリーを見ると具体的なイメージができるのではないかと思います。

インストールとデモの実行

以下のコマンドでインストールします。

$ pip install streamlit

まずは、簡単なデモを見てみましょう。以下のコマンドでアプリケーションが起動します。

$ streamlit hello

シンプルなコードで、以下のようにグラフィカルなWebアプリケーションが実装できます。
AnyConv.com__Screen recording 2022-06-03 16.43.45.gif

主な機能

以下に特徴的な機能をいくつか紹介します。

マジックコマンド

マジックコマンドとは、表示したいもの(マークダウン、データ、グラフ)の変数名を記述するだけで、アプリに表示させる機能です。例えば、変数名だけをソースコードに書くと、

x = 10
x

画面上に変数の値が表示されます。
Screenshot 2022-06-20 10.58.17.png
PandasのDataFrameを格納した変数だけを記述すると、

import pandas as pd
df = pd.DataFrame({'col1': [1,2,3]})
df

画面上にテーブルを表示できます。
Screenshot 2022-06-20 10.57.55.png
matplotlibを使えば、

import matplotlib.pyplot as plt
import numpy as np

arr = np.random.normal(1, 1, size=100)
fig, ax = plt.subplots()
ax.hist(arr, bins=20)

fig

グラフも表示できます。
Screenshot 2022-06-20 10.58.36.png

簡単なコードでのウィジェットの追加

ウィジェットを追加することは、変数を宣言することと同じです。 バックエンドを作成したり、ルートを定義したり、HTTPリクエストを処理したり、フロントエンドに接続したり、HTML、CSS、JavaScriptなどを作成したりする必要はありません。

例えば、ラジオボックスを表示したければ、streamlitをインポートして、

import streamlit as st

次の1行を記述すればOKです。

st.radio("好きなマイケルは?", ('ジャクソン', 'ジョーダン', 'ホフマン'))

Screenshot 2022-06-20 11.09.09.png

そして、戻り値に選択した値がセットされます。

簡単なデプロイ

Streamlitで開発したアプリを自身のGitHubにコミットし、Streamlit社が提供するStreamlit Cloudというクラウドサービスと連携すると、自動的にアプリをデプロイし、インターネット上に公開することができます。デプロイしたアプリは、以下のような画面で管理できます。

Screenshot from 2022-07-14 10-35-01.png

オートリロード

Streamlitで開発したアプリへのソースコードの修正は即座に反映されます。GitHubに修正をコミットすれば、Streamlit Cloud上のアプリにすぐに修正が反映されます。ローカル環境で開発している場合は、ソースコードの修正後に画面右上の「Rerun」をクリックすることで、その修正が反映されたアプリを動かすことができます。

strmlt_auto_reload.gif

応用編 〜 データ分析Webアプリの開発

では、実際にデータ分析Webアプリを開発してみましょう。ここでは、Apacheなどのアクセスログを解析するアプリをつくり、Streamlit Cloudにデプロイしてインターネットにアプリを公開します。

簡単なWebアプリの作成

まずは画面に簡単な文字列を表示するアプリケーションを作成して、GitHubにコミットしましょう。GitHubにアクセスし、適当な名前でアプリケーション用のリポジトリーを作成して下さい。

Screenshot 2022-06-06 12.30.11.png

リポジトリーを作成したら、適当なファイル名でpythonファイルを作成します。公式ドキュメントにあるとおり、streamlit_app.pyというファイル名にすると、URLにファイル名を含めずにアクセスできます(少しURLを短縮できます)。「Add new file」ボタンをクリックして、つくってしまいましょう。

Screenshot 2022-06-06 12.30.48.png

マジックコマンドで以下のコードを記述すれば、画面上にx: 10と表示することができます。

x = 10
'x: ', x 

Screenshot 2022-06-06 12.38.29.png

「Commit new file」ボタンをクリックして、保存します。Webアプリの作成は、これで完了です。

Screenshot 2022-06-06 12.32.23.png

Streamlit Cloudアカウントの登録

次に、 https://streamlit.io/cloud にアクセスします。以下のような画面が表示されるので、「Get Started」ボタンをクリックします。
Screenshot 2022-06-06 12.21.18.png
GoogleまたはGitHubの既存アカウントを使用するか、メールアドレスを入力してStreamlit Cloudアカウントを作成します。
Screenshot 2022-06-06 12.21.33.png
以降はGitHubの既存アカウントを使用します。よくあるOAuthのフローで、Streamlit CloudがGitHubアカウントの情報にアクセスすることを許可し、
Screenshot 2022-06-06 12.21.55.png
確認のためのパスワードを入力します。
Screenshot 2022-06-06 12.22.17.png
アカウントの情報などを入力したら、
Screenshot 2022-06-06 12.23.12.png
「New app」ボタンをクリックして、アプリケーションのプロファイルを作成します。
Screenshot 2022-06-06 12.23.31.png
ここで再度OAuthの同意画面が表示されるので、同意しましょう。
Screenshot 2022-06-06 12.23.56.png
Streamlit Cloudで公開するアプリの情報を入力します。ここでのアプリの情報とは、先ほど作成したアプリのGitHubリポジトリ名やパスなどです。
Screenshot 2022-06-06 12.33.04.png
「Deploy!」ボタンをクリックすると、Streamlit Cloud上でアプリが起動します。
Screenshot 2022-06-06 12.33.23.png
正常に起動できたら、以下のように画面にx: 10と表示されます。
Screenshot 2022-06-06 12.38.54.png

データ分析Webアプリの開発

簡単なWebアプリケーションができあがったので、これに機能を追加して、アクセスログを解析するWebアプリケーションにしていきましょう。

アップローダーの追加

まずは、アクセスログをアップロードする機能(アップローダー)がなければ始まりません。アップローダーは、以下のように追加できます。

import streamlit as st
uploaded_file = st.file_uploader("アクセスログをアップロードしてください。")

1.png

アップロードしたアクセスログファイルの読み込み

ファイルがアップロードできたら、st.file_uploader()の戻り値にファイルオブジェクトが格納されるので、これを使って処理を開始します。Apacheのアクセスログであれば、以下のようにpd.read_csv()で読み込めばOKです。

import pandas as pd
if uploaded_file is not None:
    df = pd.read_csv(
        uploaded_file,
        sep=r'\s(?=(?:[^"]*"[^"]*")*[^"]*$)(?![^\[]*\])',
        engine='python',
        na_values='-',
        header=None)

アクセスログファイルを読み込んだら、先頭5行を表示してみましょう。

    st.markdown('### アクセスログ(先頭5件)')
    st.write(df.head(5))

2.png

ここまでできたら、あとは変数dfに格納されたPandasのDataFrame型のアクセスログデータをいろいろな観点で解析できるでしょう。Apacheのアクセスログの解析においては、以前書いたこの記事とともにつくったノートブックがほぼそのまま使えそうだったので、これを利用することにしました。前述しましたが、Jupyter NotebookやGoogle Colabでつくったノートブックのコードがほぼそのまま活用できるのが、Streamlitのメリットと言えます。

このようにしてつくったアクセスログ解析用のWebアプリケーションがこれです。

このページの中にある「Open in Streamlit」ボタンをクリックすると、Streamlit Cloud上で動作するこのアプリケーションを試してみることができます。上記、GitHubリポジトリー内にサンプルのアクセスログがありますので、それをアップロードしてください。

顧客環境のアクセスログをStreamlit Cloudにアップロードしないように注意して下さい(Streamlit社に利用されるとは思いませんが...)。機密情報を含むアクセスログを解析したい場合は、以下の手順でローカルでこのアプリケーションを起動して下さい。

$ git clone https://github.com/k-tamura/mossala.git
$ cd mossala/
$ pip install -r requirements.txt
$ streamlit run streamlit_app.py

アクセスログ解析用のノートブックをアクセスログ解析用のWebアプリケーションに変えるために使ったStreamlitの機能を、以下にいくつか解説します。

ページタイトルとページアイコン

ページタイトルとページアイコンは、以下のように設定できます。この場合、icon.pngというファイル名でアイコンの画像ファイルをルートディレクトリーにおいておく必要があります。

st.set_page_config(page_title="メインページ", page_icon='icon.png')
st.title("Multiple OSS Access Log Analyzer")

これにより、ブラウザーのタブの部分が以下のように表示されます。
Screenshot 2022-06-21 17.31.31.png

列選択のためのウィジェット

何番目の列を解析に使用するかを選択させるための、複数選択ができる入力ボックスは、以下のように実装します。第2引数は選択可能な値のリストで、第3引数はデフォルトで選択される値のリストです。

    usecols = st.multiselect(
        '何番目の列を解析の対象にしますか?',
        [0, 3, 4, 5, 6],
        [0, 3, 4, 5, 6])

image.png

エラーメッセージの表示

st.error()でエラーメッセージを表示することができます。入力チェックはこれで実装します。

if len(usecols) == 0 or len(names) == 0:
    st.error('解析対象の列が指定されていません。')

Screenshot 2022-06-21 17.38.38.png

ヘルプテキスト

画面の項目にヘルプテキストを付けることもできます。

    help_txt = '''
        以下のフォーマット文字列を解析可能です。詳細については、[公式ページ](https://httpd.apache.org/docs/2.4/ja/mod/mod_log_config.html)を参照して下さい。

        | 列名 | フォーマット文字列 | 説明 | 
        |:-----|:-----:|:-----|
        | Remote Host | `%h` | リモートホスト |
        | Time | `%t` | リクエストを受付けた時刻 | 
        | Request | `\"%r\"` | リクエストの最初の行 | 
        | Status | `%>s` | ステータス | 
        | Size | `%b` | レスポンスのバイト数 | 
        | User Agent | `\"%{User-agent}i\"` | リクエストのUser-agentヘッダの内容 | 
        | Response Time | `%D` または `%T` | リクエストを処理するのにかかった時間 |         
        '''

    names = st.multiselect(
        'これらの列を何を意味しますか?',
        ['Remote Host', 'Time', 'Request', 'Status', 'Size', 'User Agent', 'Response Time'],
        default_names, help=help_txt)

ウィジェット用の関数の引数helpにマークダウン書式で書いた値を渡せば、次のようなヘルプテキストが表示されます。

image.png

世界地図の表示

st.map()を使用すると、地図上の指定した場所にプロットすることもできます。引数には、緯度と経度を意味するlat列とlon列を含むDataFrameを渡します。この機能とIPアドレスから場所と緯度・経度を取得するライブラリーを利用して、アクセスログのリモートホスト(アクセス元のクライアント)の地域を地図上にプロットします。

st.map(df)

Screenshot from 2022-06-21 21-52-55.png

プログレスバー

時間がかかる処理に対してはプログレスバーを表示さた方がよいでしょう。アクセスログも件数が増えると解析には時間がかかるので、以下のように大雑把な進捗状況がわかるプログレスバーを導入しています。

my_bar = st.progress(0)
# ・・・何らかの処理
my_bar.progress(10)
# ・・・何らかの処理
my_bar.progress(20)
# ・・・何らかの処理
# ・・・
my_bar.progress(100)

Screen recording 2022-06-22 15.05.15.gif

ログ出力

一般的なWebアプリケーションにおいてログ出力は重要です。Streamlitはログ出力機能を提供していないので、loggingモジュールを使って実現します。

import logging
logging.info('This message should go to the log file')

以下のコマンドで起動すれば、app.logファイルに出力できます。

$ streamlit run app.py  --logger.level=info 2>>app.log

出力された内容は、以下のようになります。

2022-06-22 16:06:01.608 This message should go to the log file

複数ページの作成

複数のページを作成したい場合は、以下のようにpagesディレクトリ配下にpythonファイルを格納しておくことで実現できます。
Screenshot from 2022-06-21 22-57-15.png

これにより、左メニューに次のようなラベルが追加され、ここをクリックするとそのページへ遷移します。ファイル名がページ名のラベルになるので注意して下さい。

Screenshot from 2022-06-21 22-59-39.png

デザインの変更

Streamlitは、.streamlit/config.tomlでいくつかの設定を行うことができます。デザインの設定もその一つで、[theme]セクションにprimaryColorなどのプロパティーを追加することで、変更ができます。以下の設定はすべてデフォルト値なので、これを設定しても何も変化はありませんが、例えば、primaryColor="blue"にすれば、チェックボックスやスライドバーなどの色が変わります。

[theme]
primaryColor="#F63366"
backgroundColor="#FFFFFF"
secondaryBackgroundColor="#F0F2F6"
textColor="#262730"
font="sans serif"

Screenshot 2022-06-22 15.35.36.png

画像の挿入

画像は、st.image()に画像ファイルのパスを渡すことで、挿入できます。

st.image('logo.png')

せっかくなので、このアプリにもロゴをつくって、それをトップページに挿入してみることにしました。
366c5aed4f9aeb472284919754bb19524fbdebd5da2e0241c52c17cc.png

アニメーション

Streamlitには以下のような遊び心のあるアニメーションも少しだけ用意されています。

st.balloons()

データ分析中の待ち時間を退屈させないために入れるとか、まあ、何らかの用途に使えるでしょうか。
animate_balloons.gif

JavaScriptで動きをつける

stc.html()を使用すれば、HTMLを書くこともできます。これを使ってAnimate.cssを読み込み、ただのメッセージに動きを付けてみます。

import streamlit.components.v1 as stc
stc.html('''
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.min.css">
<p class="animated bounceInRight">👈 左のサイドバーからアクセスログを解析したいOSSを選んで下さい。</p>
''')

animate_css.gif

グラフとテーブルを横に並べる

グラフとテーブルを横に並べるなど、画面レイアウトの調整にはst.columns()withを使いました。以下のように実装すれば、

st.markdown('### レスポンスのステータスコード')
status_df = DataFrame(df.groupby(['Status']).size().index)
status_df['count'] = df.groupby(['Status']).size().values
status_df['percentage'] = (df.groupby(['Status']).size() / len(df) * 100).values
col1, col2 = st.columns(2)
with col1:
    fig = plt.figure()
    labels = [str(n)+'xx' for n in list(df.groupby([df['Status'] // 100]).groups.keys())]
    plt.pie(df.groupby([df['Status'] // 100]).size(), autopct = '%1.1f%%', labels = labels, startangle = 90)
    plt.axis('equal')
    fig
with col2:
    status_df

このように表示されます。

Screenshot from 2022-07-14 11-42-24.png

感想

Streamlitは、高レベルのフレームワークで汎用性は低そうですが、開発したいアプリの要件を満たせれば、アプリ開発の期間を短縮する非常に良い選択肢になると思いました。逆に画面レイアウトや機能などを詳細に設計してある状況から、Streamlitでそれを実現しようとすると、かなり苦戦するのではないかと思います。まずは、Streamlitができることを大まかに把握して、アプリの要件を満たせるかどうかを検討するのがいいでしょう。

さいごに

Pythonで実装しているので、今回開発したアプリでこんなことも簡単にできそうですね。

  • 機械学習によるアクセスログのカラムの自動判別
  • 多言語対応
  • PyPI登録

参考

340
325
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
340
325

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?