マルウェア解析できるデータサイエンティストblog

マルウェアのリバースエンジニアリング技術を持つデータサイエンティストとして、データ分析/機械学習に関する情報を発信します。

データサイエンス案件でプロトタイプを素早く作るにはipywidgetsが良さそう

f:id:kazukiigeta:20210320091211p:plain

データサイエンスや機械学習の案件を進めるとき、皆さんはプロトタイプ開発に何を使ってますか?

PyQt5やTkinterなど、選択肢はいろいろあるかと思います。

私は、分析やモデル作成はJupyterlab上をやっているなら、そのままJupyterlab上でお客様に見せられるような簡易的なGUIが素早く作れたら楽だと思いました。

UI/UXを考えるのは、プロトタイプ作成⇔相手との認識合わせを繰り返してからでも良さそうだという考えです。

そこで、Jupyterlab上でインタラクティブな簡易GUIを作成できるipywidgetsを使ってみました。

今回は、ipywidgetsによるJupyterlab上での簡易GUI作成について紹介します😃

簡易GUI

今回のポイントは2点です。

  1. Jupyterlab上の余計なコードを隠す(余計な情報で相手を混乱させないための配慮)

  2. ipywidgetsで成果物の動作を見せる(実際に動かすことでお互いの認識をしっかりと合わせるため)

それぞれのやり方をこれから説明していきます。

1. Jupyterlab上の余計なコードを隠す

Jupyterlabのコードを表示/非表示できるボタン
Jupyterlabのコードを表示/非表示できるボタン

JupyterlabのIssue上で紹介されていた方法を採用して、ボタンの1クリックでコードの表示/非表示を切り替えることが出来ました。

方法は簡単で、以下のコードをエディターの先頭の方のセルに記載するだけです。

from IPython.display import HTML

HTML('''
<script src='//code.jquery.com/jquery-3.6.0.min.js'></script>
<script>
code_show=true; 
function code_toggle() {
 if (code_show){
 $('div.input').hide();
 $('div .jp-CodeCell .jp-Cell-inputWrapper').hide();
 } else {
 $('div.input').show();
 $('div .jp-CodeCell .jp-Cell-inputWrapper').show();
 }
 code_show = !code_show
}
$( document ).ready(code_toggle);
</script>
<form action="javascript:code_toggle()"><input type="submit" value="Code on/off"></form>''')

なお、jqueryのバージョンはオリジナルのv3.3.1から現時点での最新v3.6.0へ書き換えてあります。

v3.5.0でXSSの脆弱性の修正が入っていました。

攻撃者がJupyterlabにアクセスできてしまう状況であればXSSを利用するまでもなく様々な攻撃を実施することができてしまうので、この修正自体が直接このプロトタイプ開発のセキュリティを向上することはなさそうです。

しかし、データ分析の案件では機密データを扱う場面も多くあるので、セキュリティの観点から動作上問題がなければ今回に限らず最新バージョンを使うことを心掛ける必要があると思っています🔐

2. ipywidgetsで成果物の動作を見せる

ipywidgetsによる簡易GUI表示
ipywidgetsによる簡易GUI表示

こんな感じに、Jupyterlab上で素早く簡易的なGUIを作成することができます。

GIF動画で表示したGUIのサンプルコードを以下に置いておきます。

import ipywidgets as widgets
import pandas as pd
import matplotlib.pyplot as plt
from IPython.display import display


class GUI():
    def __init__(self):
        item_layout = widgets.Layout(margin='0 0 50px 0')

        self.output = widgets.Output()
        self.output.clear_output()

        self.fruits_nature = widgets.Output()
        self.fruits_nature.clear_output()

        self.button_run = widgets.Button(description='実行', button_style='danger')

        self.picked_fruits = widgets.SelectMultiple(
                        options=['りんご', 'みかん', 'ぶどう'],
                        value=['ぶどう'],
                        description='果物',
                        disabled=False,
                    ) 

        self.picked_clock = widgets.Dropdown(
                        options=['09:00', '12:00', '15:00'],
                        value='15:00',
                        description='収穫時刻',
                        disabled=False,
                    )

        self.picked_target_date = widgets.DatePicker(
                        description='予測対象日',
                        disabled=False,
                    )
    
        target_widgets = widgets.HBox(
                        [self.picked_clock, self.picked_target_date],
                        layout=item_layout)

        button_widgets = widgets.HBox(
                        [self.button_run],
                        layout=item_layout)

        tab = widgets.Tab([self.output, self.fruits_nature])
        tab.set_title(0, '予測結果')
        tab.set_title(1, '果実特性')
    
        self.dashboard = widgets.VBox([
            target_widgets, tab, button_widgets])


    def _run(self, obj):
        self.output.clear_output()
        self.fruits_nature.clear_output()

        with self.fruits_nature:
            print('収穫時刻:', self.picked_clock.value)
            x = list(range(5))
            y = [1, 5, 2, 7, 4]

            plt.plot(x, y)
            plt.show()
            
        with self.output:
            df_out = pd.DataFrame(
                {
                    'fruit': ['りんご', 'みかん', 'ぶどう'],
                    'clock': [self.picked_clock.value] * 3,
                    'yield': [54, 22, 19],
                }, index=[self.picked_target_date.value]*3)
            display(df_out)


    def display(self):
        display(self.dashboard)
        self.button_run.on_click(self._run)

GUI().display()

ドロップダウンや複数選択、チェックボックスなど、ウィジェットの種類とその呼び出し方はipywidgetsの公式ドキュメントを確認すると良いです。

最後に

ipywidgetsは、他人に分析結果を見せるとき以外にも、自分の分析用に条件をいろいろ変えながらデータを眺めるときにも便利なのでこれからちゃんと使っていこうと思います。

今回の記事はここまで。Kazuki Igetaでした😃