はじめに
default of credit card clients Data Setデータを使って、基礎分析や簡単な分類モデルの構築などを行ってきた。せっかくなので動かせるものを作ろうと思い、Dashを用いたウェブアプリの作成を行った。機械学習アプリと名乗るにはおこがましい出来だが、どうぞご容赦を・・・。
アプリのイメージ
上記データには債権者がデフォルトするかしないかを示すフラグ "default payment next month" という項目があるので、デフォルトの分類モデルを作る。アプリのイメージは以下。
- ロジスティック回帰、決定木、サポートベクターマシンの3種類からモデルを選択
- 説明変数(量的変数、質的変数)を複数選択
- 上記2項目を設定後、決定ボタンを押すことで学習開始
- 学習結果を表示
とりあえず動くものができればいいので、機械学習の精度とデザインは一旦置いておく。
コールバック関数の引数State
今回のアプリを作成するにあたり、Dashでウェブアプリ作成①、Dashでウェブアプリ作成②、Dashで世界遺産を世界地図にプロットあたりで学習したこと以外で、dash.dependenciesライブラリの__State__が便利だったので書いておく。
もともとコールバック関数の引数としては Input(と Output )しか知らなかったため、上記1および2にて項目を選択する度にコールバック関数が呼び出されてしまっていた。これはイメージしたものと違うなと感じ調査したところ、State なるものを見つけた。Input と使い方はほぼ同様だが、State はコールバック関数を呼び出すトリガーにはならないらしい。上記1と2で選択した情報は State としてコールバック関数に渡して、3の決定ボタンをトリガーに State の情報をもとに学習するようにすれば、イメージ通りのものが作れるはず。
上記を踏まえたコードは以下に示す。(①CSV形式に直したデータセット、②標準化およびダミー変数化などの前処理後データが必要。過去記事ありきのコードとなってしまっているため、このままでは実行できない。。。)
# Run this app with `python app.py` and
# visit http://127.0.0.1:8050/ in your web browser.
import dash
import dash_html_components as html
import dash_core_components as dcc
from dash.dependencies import Input, Output, State
import plotly.express as px
import pandas as pd
# For models
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve, roc_auc_score
from sklearn.linear_model import LogisticRegression
from sklearn.tree import DecisionTreeClassifier
from sklearn.svm import SVC
# from sklearn.preprocessing import StandardScaler
df = pd.read_csv(
"c:/***/data/default_of_credit_card_clients.csv", header=1, index_col=0)
col = df.columns.values
quantity_col = col[[0, 4, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22]]
quality_col = col[[1, 2, 3, 5, 6, 7, 8, 9, 10]]
df_p = pd.read_csv(
"c:/***/preprocessed_data.csv", header=0, index_col=0)
col_p = df_p.columns.values
# quantity_col_p = df_p.iloc[:, :14]
quality_col_p = df_p.iloc[:, 14:-1]
external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css']
app = dash.Dash(__name__, external_stylesheets=external_stylesheets)
app.layout = html.Div([
html.H4(children='default of credit card clients Data Set'),
html.Div([
html.Label('Training model'),
dcc.Dropdown(id='model',
options=[
{'label': 'Logistic Regression',
'value': 'Logistic Regression'},
{'label': 'Decision Tree', 'value': 'Decision Tree'},
{'label': 'SVM', 'value': 'SVM'}
],
value='Logistic Regression'
),
html.Label(children='Quantity column'),
dcc.Dropdown(id='quantity-col',
options=[{'label': i, 'value': i} for i in quantity_col],
value=[i for i in quantity_col],
multi=True
),
html.Label(children='Quality column'),
dcc.Dropdown(id='quality-col',
options=[{'label': i, 'value': i} for i in quality_col],
value=[i for i in quality_col],
multi=True
),
html.Button('Enter', id='enter-button', n_clicks=0)
]),
html.H5('Result'),
html.Div(id='result')
])
def make_dummycol(column): # ダミー変数を含む列名のリストを作成
dummycol = []
for c in column:
dummycol += [c + "_{}".format(i) for i in range(-1, 9)]
l = [cp for cp in quality_col_p if cp in dummycol]
return l
def train(model, quantity_col, quality_col): # 選択モデルとデータを使用して学習、AUCスコアを返す
col_list = list(quantity_col) + make_dummycol(quality_col)
X = df_p[col_list]
Y = df["default payment next month"]
X_train, X_test, Y_train, Y_test = train_test_split(
X, Y, test_size=0.2, random_state=0)
if model == 'Logistic Regression':
lr = LogisticRegression(max_iter=2000)
lr.fit(X_train, Y_train)
THRESHOLD = 0.30
Y_pred = np.where(lr.predict_proba(X_test)[:, 1] > THRESHOLD, 1, 0)
elif model == 'Decision Tree':
dt = DecisionTreeClassifier(max_depth=4)
dt = dt.fit(X_train, Y_train)
Y_pred = dt.predict(X_test)
elif model == 'SVM':
svm = SVC(kernel="rbf", gamma="scale")
svm.fit(X_train, Y_train)
Y_pred = svm.predict(X_test)
return html.Div([model, ": AUC Score:", round(roc_auc_score(Y_test, Y_pred), 3)])
@app.callback(
Output('result', 'children'),
Input('enter-button', 'n_clicks'),
State('model', 'value'),
State('quantity-col', 'value'),
State('quality-col', 'value'))
def show_result(enter, model, quantity_col, quality_col):
return train(model, quantity_col, quality_col)
# print("Coefficients:", lr.coef_[0])
# print("Intercept:", lr.intercept_[0])
if __name__ == '__main__':
app.run_server(debug=True)
実行結果は以下のようになる。(以下GIFでは為井していないが、SVMは他2つと比べ実行時間が長い。)
おわりに
各モデルごとのパラメータ修正やその他結果の表示など修正すべき点は多々あるが、一旦ここまで。動くものを作るのはおもしろい。