Streamlitで確率分布のシミュレーションアプリを作ってみた

Streamlitで確率分布のシミュレーションアプリを作ってみた


巷でFlaskはオワコンと言わしめている、StreamlitというMLツールを使ってみました。
Streamlitは、Pythonスクリプトだけでwebアプリを作成できるツールです。

公式ページ曰く、Streamlitはデータサイエンティストや機械学習エンジニアがほんの数時間で美しくパフォーマンスの高い を作るための最も簡単なフレームワークとのこと。

Streamlit’s open-source app framework is the easiest way for data scientists and machine learning engineers to create beautiful, performant apps in only a few hours! All in pure Python.
出典: https://www.streamlit.io/

今回はお試しということで、代表的な確率分布である二項分布、ポアソン分布の描画をStreamlitでやってみます。

※弊社ブログにてStreamlitを使用したWebアプリの作成についていくつか記事を書いていますので、そちらもご参照ください。
・StreamlitでベイジアンABテストができるWebアプリを作成した記事


・Streamlitでポケモンを生成するGANを用いたWebアプリを作成した記事

コードはGitHubにあげています。

前提

上記で紹介したコードは、以下のディレクトリ構成となっています。

.
├── Dockerfile
├── README.md
├── docker-compose.yml
├── main.py #アプリを実装
├── poetry.lock
└── pyproject.toml

また、実行環境は以下を前提とします。

  • MacあるいはLinuxであること
  • Dockerをインストールしていること

ですが、もしDockerを使いたくないという場合は、直にStreamlitや他のライブラリをインストールしてください。

pip install streamlit
pip install matplotlib
pip install seaborn

コードの説明

使用するStreamlit API

今回使用しているStreamlit APIのメソッドは以下になります。
他にもたくさんメソッドが用意されているので、詳しくは公式ドキュメントをご参照ください。

対象箇所メソッド概要
サイドバーst.sidebar.markdown()markdownで文章を作成できる。サイドバーにst.write()は存在しない。
サイドバーst.sidebar.number_input()数値入力ウィジェットを作成できる
メインコンテンツst.header()ヘッダーを作成できる
メインコンテンツst.subheader()サブヘッダーを作成できる
メインコンテンツst.pyplot()matplotlib.pyplotでグラフを表示できる
メインコンテンツst.latex()LaTeX記法で数式を表示できる
メインコンテンツst.text()テキストを表示できる

main.py

アプリを実装しているmain.pyについて説明します。
まず、必要なライブラリをインポートし、乱数シードを固定します。

import streamlit as st
import pandas as pd
import numpy as np
import random
import matplotlib.pyplot as plt
import seaborn as sns
sns.set()
# 乱数シード固定
np.random.seed(0)

次に、サイドバーを実装します。
サイドバーでは、ポアソン分布のパラメータ \( \lambda \) 、二項分布のパラメータ \( n,\, p \) を入力できるようにします。
なお、ポアソン分布、二項分布のパラメータ間で \( \lambda = n \cdot p \) (一定)が成立するようにしています。
したがって、 \( \lambda \) と \( n \) を入力すると、 \( p \) が算出/表示されるように実装します。

\( \lambda = n \cdot p \) のもとで、 \(n \to \infty,\, p \to 0\) とすると、二項分布がポアソン分布に漸近する性質をシミュレーションしたいためです。
# sidebarにおけるパラメータ設定
st.sidebar.markdown('Set Parameter')
lambda_ = st.sidebar.number_input(
  'input lambda',
  min_value=1,
  max_value=100,
  value=10
)
n = st.sidebar.number_input('input n', value=50)
p = lambda_ / n
st.sidebar.markdown(f'calculated p is **{p}**')
size = st.sidebar.number_input('sample size', value=1000)

次に、設定したパラメータをもとにグラフ化します。

st.header('Comparison between Poisson and Binomial')
# グラフ設定
fig = plt.figure(figsize=(20,10))
ax = fig.add_subplot(111)
# ポアソン分布
points = np.random.poisson(lambda_, size=size)
sns.distplot(points, hist=False, bins=100, ax=ax, label='Poisson')
# 二項分布
points = np.random.binomial(n, p, size=size)
sns.distplot(points, hist=False, bins=100, ax=ax, label='Binomial')
ax.legend(loc='upper right', fontsize='xx-large')
fig.tight_layout()

最後に、メインコンテンツにポアソン分布、二項分布の2つのグラフを可視化し、加えて確率分布の数式表現をLaTeXで記述します。

# 可視化
st.subheader('Visualization of distributions')
st.pyplot(fig)

# 数式表現
st.subheader('Mathematical expression')
st.text('Poisson distribution is defined by:')
st.latex(r'''
Po(\lambda) = \frac{\lambda^x e^{-\lambda}}{x!}
''')
st.text('Binomial distribution is defined by:')
st.latex(r'''
Bin(n, p) = {}_n \mathrm{C} _x p^x (1-p)^{n-x}
''')

コードの実行

上記のmain.pyを作成し、Dockerfileと同一ディレクトリにて以下を実行します。

docker-compose up -d

もし、Dockerを使っていない場合は、以下のコマンドを代わりに実行します。

streamlit run main.py

その後、http://localhost:8501にアクセスすることで、実装したアプリを操作できます。

Streamlitで作成したアプリの様子

Streamlitで実装したアプリがどのように動作するのかを動画にしました。

最後に

Streamlitを使うことで、HTMLやCSSを意識せずとも、Jupyter Notebookで記述しているようなPythonの分析コードだけで手軽にアプリを実装できることがわかりました。
今回のようにパラメータに応じてどのように結果が変わるのかを可視化したい場合はかなり有用なツールだと思います。

TableauやGoogle DataPortalといった既存のBIツールとStreamlitとの棲み分けですが、パラメータを引数にした複雑な処理結果を可視化したいのであればStreamlit一択だと思います。
GANのデモなんかはまさしくStreamlitでアプリ実装すると良いと思います。

一方、すでにJupyterで分析結果をチームで共有していて事足りている場合は、わざわざStreamlitでアプリを実装する必要はないと感じました。
これは、Streamlitを使えば手軽にアプリを実装できるとはいえ、Jupyterで書いたコードをStreamlit用に変換するのに手間がかかるためです。
閲覧者が設定したパラメータに応じて、BIツールではできない複雑な処理結果をインタラクティブに可視化したい場合にStreamlitは有効だと思いました。