Dashで機械学習ができるWebアプリを作る [Step4]
Dashを使って、機械学習をさせるWebアプリケーションを作ろうStep4 !
これまでの流れはこちら
流れ(おさらい)
Step1: タイトルとデータアップロードの枠だけ作り、cssでいい感じに表示させる
Step2: 単純な線形モデルを作り、グラフとスコアを表示させる
Step3: モデルを選択するドロップダウンを作って、選択したモデルに応じて出力結果が変わるような動的なページを作る
今回はここ↓
Step4: ファイルをアップロードし、データフレームとして表示させる
Step5: アップロードしたデータを読み込んで学習させるようにする
Step4での完成イメージ
アップロード部分にデータを投げたら、データフレームとして中身が見えるようになります!
わーい。
はい。
これを行うためのcallback関数は、がっつり公式ドキュメントを参考にさせていただいています。
まず、アップロードする入れ子を、layout
の中のアップロード部分の下に記述してください。
dash_table.Datatable
というモジュールを使います!
# アップロードしたファイルをデータテーブルとして表示させる部分 html.Div( children=[ dash_table.DataTable( id='output-data-upload', column_selectable='multi', fixed_rows={'headers': True, 'data': 0}, style_table={ 'overflowX': 'scroll', 'overflowY': 'scroll', 'maxHeight': '250px' }, style_header={ 'fontWeight': 'bold', 'textAlign': 'center'} ) ], style={ 'height': '300px' }), html.Br(),
今回はそのcallback関数の中身だけ、見てみましょう。
全コードは、Githubのapp4.pyに載せてあります。
# アップロードしたファイルをデータフレームとして読み込むための関数 def parse_contents(contents, filename): content_type, content_string = contents.split(',') decoded = base64.b64decode(content_string) try: if 'csv' in filename: # Assume that the user uploaded a CSV file df = pd.read_csv( io.StringIO(decoded.decode('utf-8'))) elif 'xls' in filename: # Assume that the user uploaded an excel file df = pd.read_excel(io.BytesIO(decoded)) except Exception as e: print(e) return html.Div([ 'There was an error processing this file.' ]) data_ = df.to_dict('records') columns_ = [{'name': i, 'id': i} for i in df.columns] # データフレームの中身を送る return [data_, columns_] @app.callback([Output('output-data-upload', 'data'), Output('output-data-upload', 'columns')], [Input('upload-data', 'contents')], [State('upload-data', 'filename')]) def update_output(list_of_contents, list_of_names): # ファイルがない時の自動コールバックを防ぐ if list_of_contents is None: raise dash.exceptions.PreventUpdate contents = [parse_contents(c, n) for c, n in zip(list_of_contents, list_of_names)] return [contents[0][0], contents[0][1]]
app.layout
を記述したあと、一旦、parse_contents
関数を定義し、そのあとにその関数を使ってcallbackを記述しています。
簡単な解説
ファイルがアップロードされると、その中身はbase64にエンコードされた文字列としてフロントエンドに保持されます。
中身を使うには、dashのコールバックにおいて、contents
プロパティで呼び出し、デコードして利用します。
It’s stored in the “front-end” as a base64 encoded string and transferred to your Python code via the dash callbacks via the contents property. Once its in your python callback, you can do whatever you want with it: save it to a file (which is one way for it to be reused in other callbacks: you just have to be careful about file naming), read it into a dataframe, etc.
引用元: https://community.plot.ly/t/data-from-file-in-dash-upload-component/4922/13
公式では、Output
としてdivのchildrenそのものを返すようにしているのですが、
それだと後々、データテーブルの中のデータをcallbackのInput
として再び読み込む際に面倒になる*1ことが分かったので、
このようにdash_table.Datatable
の中の要素2つ(componetn_property = data
と、component_property=columns
)を返すようにしました。
そして、Inputとして同列に並んでいるState
は、
コールバックが自動で引き起こされないようにするための「ストッパー」の役割を果たします*2。
ただ、今回、複数のOutputを設定したからか、Stateを定義してもエラーが出てしまった*3ので、
if list_of_contents is not None: raise dash.exceptions.PreventUpdate
でエラー処理をしました。
State
やら例外処理やらをやらないといけませんでしたが、これで無事データアップロード機能が完成したので、
お次、Step5でようやく、このデータ読み込みと機械学習を連携させて最終アプリの完成になります!
ここまで読んでくださりありがとうございました〜