redash + Google Colabによる分析環境

ゲームコミュニティ事業部のデータエンジニア(β版)の池田です。
この記事は、Tech KAYAC Advent Calendar 2019 の7日目です。
今回もredash周りの話で、Lobiでの分析事例の話をしていきたいと思います。
(本ブログではredashおじさん化していますね。 )

Lobiでの分析環境の概要

ゲームコミュニティ事業部では主要サービスとして Lobi を開発・運営しています。
現在のLobiにおける分析環境は、以下の図のようになっています。

f:id:ikeda-masashi:20191204165035j:plain
分析環境の図

アプリケーションが行動ログやアクセスログを出力し、それをFluentdやKinesis Data Firehoseを使ってS3バケットへ転送しています。その後@fujiwaraさんのrinを使ってRedshiftにロードしています。この周辺に関しては、ソーシャルゲーム事業部での記事と同様ですので、詳しくはそちらをご参照お願いします。

ソーシャルゲームのカスタマーサポートを支える行動ログとredash - KAYAC engineers' blog

redshiftにロードされた行動ログやアクセスログなどをビジュアライズする環境としてはredashを活用しております。 つい最近まで、このredashは秘伝化のタレのようになった古のインスタンスで動いていましたが、今ではECSのFagate環境で動いています。その移行に関しては先日の記事を読んでいただければ幸いです。

秘伝のredash v1.0.3 から redash v8.0.0 on ECSになるまで - KAYAC engineers' blog

redashからredshift以外にも、アプリケーションサーバーが参照しているDBのバックアップやGoogle Spreadsheetなど様々なデータにアクセスできるようにしており、基本的にはredash上でデータをビジュアライズする形でデータを図示して情報共有を行います。例えば以下の用な感じでビジュアライズできます。

f:id:ikeda-masashi:20191204171729j:plain
  これは、直近一週間のスタンプ仕様数ランキングですね。 (小ネタですがredashは一部のhtmlタグはそのまま表示されます。imgタグやaタグを使ってTableを便利に改変できます)

redashはLobiの運営チームが参照する以外にもGoogle Colaboratory(通称 Google Colab)というプロダクトが参照することがあります。このGoogle Colabとredashの組み合わせが今回の記事の本題となります。

Google Colabとの合わせ技

前年のAdventCalendarにて、間接的にredashにpythonデータソースを加えることで、データを柔軟に加工できるという話をしました。

techblog.kayac.com

移動平均や四分位点、相関係数等であれば、pythonデータソースを使うことで割と楽に算出できます。
しかし、多変量解析やベイズモデリング、機械学習などを使った分析をredash上で行うのは以下の理由であまり良いとは言えません。

  • 多種多様なpythonパッケージをインストールするのは気軽ではない。
  • 反復型学習アルゴリズムなどは、redashのクエリ実行時間が長くなりキューが詰まる
  • redashのビジュアライズは簡単だが限界がある。
    (ネットワーク図や樹形図、グラフ上でのテキストの書き込みができない)

そこで登場するのがGoogle Colabです。
Google Colabはクラウドで使用できるJupyter ノートブック環境です。
このGoogle Colabでは、pipを使ったパッケージインストールやTensorflowの使用も可能で、Google社の持つ強力なコンピュータリソースでもってデータの分析を進めることができます。
Lobiでは凝った分析をする場合、redashで分析対象となるデータを整形し、以下のようにredash APIを用いて、Google Colabにデータを送ります。 f:id:ikeda-masashi:20191204185205j:plain

例えば、redashのapiがhttps://my.redash.host/api/queries/2000/results.csv?api_key=abcde... だとすると、 Google Colab側でのデータを受け取るコードの以下のようになります。

import pandas as pd
url="https://my.redash.host/api/queries/2000/results.csv?api_key=abcde..."
df=pd.read_csv(url)

これはすごく素朴な例ですが、ユーザー毎のAPI Keyを利用することでより柔軟にredashからデータを取得することもできます。 (redashにはクエリ毎のAPI Keyとユーザー毎のAPI Keyの2種類があります。)
次の例は、パラメータ付きのredashクエリについて、複数のパラメータでデータを取得するような例です。 取得元redashクエリの想定としてはid:2001でuidというパラメータが一つある想定です。

#@markdown redashからデータを取得する。
#先頭に!をつけるとshellとして実行できる。これでpip installでパッケージ追加可能
!pip install redash-dynamic-query

from redash_dynamic_query import RedashDynamicQuery
from io import StringIO
import pandas as pd
from google.colab import drive

#Google Driveをこの1行でマウントできます。出力でGoogle認証を求められます。
drive.mount('/content/drive')

#設定関連
drive_path = "drive/My Drive/"
data_file = 'df.pkl'
query_id = 2001
uids = ['abc','def']

# RedashDynamicQueryという便利なパッケージがある。
redash = RedashDynamicQuery(
    endpoint='https://<your redash host>',
    apikey='<your user api key>',
)
#クエリパラメータを変更しながら1回ずつpandas DataFrameに入れる。
df_tmps = []
for uid in uids:
  bind = {
    'uid': uid,
  }
  result = redash.query(query_id, bind, as_csv=True)
  data = StringIO(result)
  df_tmps.append(pd.read_csv(data))

# DataFrameを結合して、driveに保存と表示
df = pd.concat(df_tmps).reset_index().drop('index', axis = 1)
pd.to_pickle(df, drive_path + data_file)
df.head()

この例では、Google Driveを一時的にマウントして、そこに取得したデータをpickleで保存することもしています。
Google ColabではGoogle DriveやGoogle Spreadsheetなどの他のGoogleサービスと柔軟に連携するライブラリが用意されています。チームで運用する際にredashのAPI Keyも他のGoogleサービスと併用して利用することでよりセキュアに取り扱うことも可能です。
このようにして、pandasのDataFrameとしてGoogle Colab上にデータを読み込めれば、あとは普通のpythonと変わりないので好き放題データを分析することができます。

Google Colab上でのベイズA/Bテスト事例

データを連携するだけの話だと味気がないので、最後にベイズA/Bテストを行う事例を紹介します。
この事例では、ある機能実装を検討しているときに、その機能を実装することである行動がより起こりやすくなることを期待しています。
そこで、Lobi上に存在しているグループを機能を入れたA群と機能を入れていないB群にランダムで分けてA/Bテストにチャレンジしました。 redashで行動ログからA群とB群のグループに関してそれぞれについて、ある行動が起きた=1 として ある行動が起きなかった=0という観測データを用意しました。data_Aとdata_Bにはarray([0, 1, 0, ..., 0, 0, 0]) という感じの配列がある状態で、pymc3パッケージを使って分析することができます。

import pymc3 as pm
import pickle

model = pm.Model()
with model:
    prob_A = pm.Uniform('prob_A',0,1)
    prob_B = pm.Uniform('prob_B',0,1)
    
    delta_prob = pm.Deterministic('delta_prob', prob_A - prob_B)
    
    obs_A = pm.Bernoulli('obs_A', prob_A, observed=data_A)
    obs_B= pm.Bernoulli('obs_B', prob_B, observed=data_B)

with model:
    trace = pm.sample(20000)

with open(drive_path+"trace.pkl", "wb") as f:
    pickle.dump(trace, f)   

これはMCMCと呼ばれる方法で、A群とB群のある行動が起きる確率とその確率の差に関しての確率分布をベイズ的に推定しています。 上記のコードを使って得られたtraceデータを用いてグラフを描画してみます。

%matplotlib inline

# サンプリング結果を変数に格納
prob_A_samples = trace["prob_A"][2000:]
prob_B_samples = trace["prob_B"][2000:]

# A群とB群の分布をプロット
plt.figure(figsize=(15, 6))
plt.style.use('seaborn-darkgrid')
plt.rcParams["font.size"] = 15
plt.rcParams["font.family"] = "IPAGothic"
plt.rcParams["text.usetex"] = False
plt.subplot(2,1,1)
plt.title('Prob', fontsize=11)
plt.hist(prob_A_samples, bins=50, histtype="stepfilled", label='A群',density=True, alpha=0.5)
plt.hist(prob_B_samples, bins=50, histtype="stepfilled", label='B群',density=True, alpha=0.5)
ylim = plt.ylim()
plt.vlines(np.median(prob_A_samples), 0, ylim[1], linestyle="-")
plt.vlines(np.median(prob_B_samples), 0, ylim[1], linestyle="-")
plt.legend()

delta_samples = trace["delta_prob"][2000:]
# A群とB群のθの差をプロット
CI = pm.stats.hpd(delta_samples, alpha=0.05)
plt.subplot(2,1,2)
plt.title('Delta', fontsize=11)
plt.hist(delta_samples, bins=50, histtype="stepfilled", density=True, alpha=0.5)
ylim = plt.ylim()
plt.vlines(np.median(delta_samples), 0, ylim[1], linestyle="-", label="Median")
plt.vlines(CI[0], 0, ylim[1], linestyle="--", label="95% CI")
plt.vlines(CI[1], 0, ylim[1], linestyle="--")
plt.legend()

plt.show()

モザイクの関係上、全く同じデータではありませんが、以下のような形でグラフが出てきます。 f:id:ikeda-masashi:20191205143731p:plain

このグラフからは視覚的に機能の良し悪しを把握することができます。 これは、上段にはある行動が起きる確率の推定された分布が描画されていて、下段には上段の確率の差の推定された分布が描画されています。 上段はある機能をONにしたA群のほうが右側によっていて、下段からは、機能をONにすることである行動が起きる確率が1.4% ( 95%hpdi 0.0%~2.8%)で向上するっぽいぞ!ということが読み取れます。

Lobiではこのような形でredashとGoogle Colabを組み合わせて統計的な処理を行い分析を試みています。

まとめ

この記事ではLobiでの分析環境を図で表し、redashとGoogle Colabの合せ技の例を紹介し、ベイズA/Bテストをする事例を紹介しました。ベイズA/Bテストについては、一般的なA/Bテストツールを使えば楽に実現できますが、ちょっと凝った指標とかについても調べたい場合はかゆいところに手がとどかない感じがします。今回のようにredashとGoogle Colabを使えば、そのかゆいところにも手が届くので皆さんも使ってみてはどうでしょうか?他にもTensorFlowを使った分析とか多変量解析とかもできるのでおすすめです。

明日はbeintoさんが「Twitter API 」or「python-opencv」のどっちかを書くという噂を聞いています。お楽しみにー