KaggleのTitanicチュートリアルをTabPy(Tableau + Python)で解く方法


BIツールTableauとPythonを連携するフレームワークであるTabpyを使って、Kaggle1のチュートリアルであるTitanicデータセット2を題材に機械学習モデルの構築と結果の可視化までやってみました。
EDA(探索的データ分析)3や特徴量エンジニアリング4とかをしっかりやって真剣にモデル構築したわけではなく、あくまでTabPyをつかった機械学習と結果の可視化をテーマに説明します。

環境

  • Python 3.7.2
  • Tableau 2018.1.6

TabPyの準備

以下のサイトで詳しく説明されていますが、Dockerコンテナでサーバを起動する方が楽だと思います。
Tabpy - Tableau + Python 連携 を使ってみよう!(その1:Tabpy導入編)
なので、今回はDockerコンテナでTabpyサーバーを起動する方法を説明します。
Dockerのインストール方法

Dockerfileを作成

以下のDockerfileを作成します。
Pythonベースイメージにtabpyをインストールし、サーバー起動コマンドを実行するだけの簡単なものです。

Dockerfile
FROM python:3.7-slim

RUN pip install tabpy==1.0.0

CMD ["tabpy"]

Tabpyサーバーの起動

DockerfileをもとにDockerイメージをビルドし、コンテナ(Tabpyサーバーのコンテナ)を起動させます。

# Dockerイメージのビルド
docker build -t tabpy .
# コンテナ起動(9004ポートをコンテナとローカルで繋ぐ)
docker run -p 9004:9004 tabpy

Tableauでの操作

データ準備

以下、KaggleからTitanicデータセットをダウンロードします。
Titanic: Machine Learning from Disaster
学習用データのtrain.csvとテストデータのtest.csvをTableauで読み込みます。
このとき、下図のようにtrain.csvtest.csvをユニオンさせます。5

Titanicデータセットは全レコード数が1309と、かなり軽量なので、csvファイルのまま分析を進めても支障ありません。
ただ、データ量が多い場合はデータの抽出を実施し、hyperファイル(あるいはtdeファイル)を生成して分析する方が良いです。
圧倒的に処理速度が向上します。

計算フィールド作成

次に計算フィールドを作成していきます。

LogisticRegressionフィールド

TaPpyで機械学習を行うための肝となる箇所です。
大まかに以下の流れで処理が行われます。

  1. Tableauの集計関数or定数データをINPUT
  2. Tabpy serverで機械学習を実施、結果を返却
  3. TableauにOUTPUT

詳しくは以下を参照ください。
Tabpy - Tableau + Python 連携 を使ってみよう!(その2:入出力の仕組みと簡単な計算)

以下が今回作成したモデルになります。
sckit-learnのロジスティック回帰モデルを使用し、デフォルトのパラメータのままfit, predictしています。

SCRIPT_STR('
import numpy as np
import pandas as pd
from sklearn.linear_model import LogisticRegression

#引数をDataFrameに格納
survived = pd.DataFrame(_arg1)
sex = pd.DataFrame(_arg2)
age = pd.DataFrame(_arg3)
fare = pd.DataFrame(_arg4)
table_nm = pd.DataFrame(_arg5)
full = pd.concat([survived,sex,age,fare,table_nm],axis=1)
full.columns = ["survived","sex","age","fare","table_nm"]

#学習用データとテストデータに分割
train = full[full["table_nm"]=="train.csv"]
test = full[full["table_nm"]=="test.csv"]

#欠損値補完(学習データのage, fareの中央値を使用)
inpute_age = train["age"].median()
inpute_fare = train["fare"].median()
train["age"].fillna(inpute_age, inplace=True)
train["fare"].fillna(inpute_fare, inplace=True)
test["age"].fillna(inpute_age, inplace=True)
test["fare"].fillna(inpute_fare, inplace=True)

#ダミー変換(sex)
train = pd.get_dummies(train, drop_first=True, columns=["sex"])
test = pd.get_dummies(test, drop_first=True, columns=["sex"])

#ターゲット変数
train_X = train.drop(["survived","table_nm"], axis=1)
train_y = train["survived"]
test_X = test.drop(["survived","table_nm"], axis=1)
X = pd.concat([train_X,test_X], axis=0)

#ロジスティック回帰モデルを使って学習
LR = LogisticRegression()
LR.fit(train_X, train_y)
rs = LR.predict(X)
return rs.tolist()
',MAX([Survived]),MAX([Sex]),SUM([Age]),SUM([Fare]),MAX([Table Name])))

scikit-learnの使い方は、通常のKaggleにチャレンジする場合と同じです。
INPUTのデータ項目に対して集計関数を適用したり、OUTPUTはlist型にしたりする必要があるので、その点だけ注意してください。

当てはめ成否

モデルの当てはめ結果と実際の生死を比較し、当てはめ失敗or成功かを判別するカラムを計算フィールドで作成します。

if max([Survived]) != [LogisticRegression] then '失敗'
else '成功'
end

Tableauでモデルの当てはめ結果を可視化

これでいろいろ可視化できます。
以下がロジスティック回帰モデルの当てはめ結果を可視化したシートになります。

下図は少々のEDAと学習データへの当てはめを可視化したダッシュボードになります。
左側は今回のモデルのINPUTに使った特徴量であるAge, Sex, Fareとターゲット変数であるSurvivedとの分布を示し、右側はモデルの当てはめ結果を可視化したものです。

テストデータの予測

LogisticRegressionフィールドを整数型に変換し、「PassengerId」単位で集計させます。
できたクロス集計表をcsvファイルでエクスポートし、以下のテストデータ用の「PassengerId」に絞るとKaggleに提出できます。

  • 「PassengerId」1~891:学習データへの当てはめ結果
  • 「PassengerId」892~1309:テストデータの予測

まとめ

KaggleのKernelをみてみると、Pythonのpandasを使ってデータをごりごり加工し、matplotlibやseabornを使って可視化するのが定石になっています。
ただ、データの可視化の観点でいえばPythonのライブラリよりもTableauはかなり優れています。
なによりレスポンスが速く、すいすいアドホック分析ができます。
一方、機械学習を実施する場合は、Pythonでやった方が楽だなぁという印象でした。
Tabpyで機械学習できなくもないですが、いろいろと制約が多いです。


  1. お題のデータセットをもとに予測モデルを構築し、予測結果の精度を競うコンペです。データセットは様々で、過去にはmercariやリクルートがデータ提供したコンペもありました。 

  2. Kaggleのチュートリアル的なコンペです。映画でおなじみのタイタニック号について、乗客のプロフィール情報をもとに生存・死亡を予測します。 

  3. 仮説ありきでデータセットの特徴量やターゲット変数の分布・相関なんかを分析していく工程です。いかにデータを可視化できるかが重要です。 

  4. データ前処理に該当する工程で、データ型の変換、標準化などなど、モデルが良い予測ができるようにいろいろと特徴量を加工します。 

  5. test.csvにはSurvivedカラムがなく、ユニオンできないと思われるかもしれませんが、自動的にnull埋めされるのでご心配なく。