概要
どこもかしこもA/Bテストを行っていると言ってますが、それってAテストBテストじゃないですか?
Aパターンを測定した後にBパターンを測定するのはA/Bテストとは言い難いと思います。
同時期に行っていないというのが大きな要因です。
AパターンBパターンを同時期に測定しているところは稀だったりします。
バンディットアルゴリズムを使えばA/Bテストはおろか、A/B/Cだろうが、A/Bで開始して途中からC/Dパターンを追加だろうが簡単に行うことができます。
1.テンプレートの登録
まず始めにAパターン、Bパターンのテンプレートを用意します。
このテンプレートというものはMVCフレームワークのV部分だと思ってください。
このテンプレート名をJubatusのバンディットアルゴリズムに登録しておきます。
python set_template.py [テンプレートファイル名(index_a.phpとか)]
#!/usr/bin/env python
# coding: utf-8
host = '127.0.0.1'
port = 9199
name = 'A/B TEST'
import sys
import jubatus
from jubatus.common import Datum
def register_arm(client, arm):
client.register_arm(arm)
if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
print 'Usage: # python %s templateName ' % argvs[0]
quit()
template_name = argvs[1]
client = jubatus.Bandit(host, port, name)
register_arm(client, template_name)
2.試したいテンプレートの選択
テンプレートを選択する直前でJubatusに問い合わせます。
Codeigniterの場合は
$this->load->view('index.php');
の直前になります。
exec("python ./select_template.py" , $ret1); #index_a.phpとかを返してくれることを期待している
$this->load->view(trim(implode('', $ret1)); #index_a.phpを呼ぶことを想定
とすると、Jubatusが返してくれたテンプレートを読むことができます。
テンプレート名が正しくPHPファイル名になっていれば表示されると思います。
Pythonを実行することになるので負荷には注意してください。Exceptionを正しく設定した方が良いと思います。
#!/usr/bin/env python
# coding: utf-8
host = '127.0.0.1'
port = 9199
name = 'A/B TEST'
import sys
import jubatus
from jubatus.common import Datum
def get_template(client, player):
reward_point = 0.0 #表示ポイント 表示時は0ポイントとした場合
arm = client.select_arm(player)
client.register_reward(player, arm, reward_point ) #取得した時にポイントを付与しておかないと同じarmばかり引くため
return arm
if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
user_id = u'none'
if (argc == 2):
user_id = argvs[1]
client = jubatus.Bandit(host, port, name)
print get_template(client, user_id )
3.施策達成時のポイントを登録
施策達成時は様々なパターンがあると思います。指定ページへの遷移や経過時間やユーザ登録などです。
その場合には報酬を設定してあげましょう。
exec("python ./set_reward.py index_a.php"); #index_a.phpを表示した時に施策達成
#!/usr/bin/env python
# coding: utf-8
host = '127.0.0.1'
port = 9199
name = 'A/B TEST'
import sys
import jubatus
from jubatus.common import Datum
def set_reward(client, player, arm):
reward_point = 1.0 #施策達成時のポイント 施策達成時は1ポイントとした場合
client.register_reward(player, arm, reward_point )
if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
print 'Usage: # python %s templateName [userId]' % argvs[0]
quit()
template_name = argvs[1]
user_id = u'none'
if (argc == 3):
user_id = argvs[2]
client = jubatus.Bandit(host, port, name)
set_reward(client, user_id, template_name)
流れ
1.テンプレートの登録
サーバのコマンドラインから実行します。
python set_template.py index_a.php
python set_template.py index_b.php
当たり前ですが最低2つは登録してください。
2.表示(Codeigniterの場合)
表示ページ内でJubatusからページ名を取得します。
exec("python ./select_template.py" , $ret1); #index_a.phpとかを返してくれることを期待している
$this->load->view(trim(implode('', $ret1)); #index_a.phpを呼ぶことを想定
3.達成時
達成ページの表示時に報酬を設定します。
index_a.php は引数などで持ち歩いている必要があります。
exec("python ./set_reward.py index_a.php"); #index_a.phpを表示した時に施策達成
4.途中でパターンを追加
A/Bテストが落ち着いてきたら次の施策を打ちたいことだと思います。
ページを作成した後にそのページのテンプレート名をJubatusに登録するだけで配信され始めます。
python set_template.py index_c.php
python set_template.py index_d.php
python set_template.py index_e.php
AとBでどちらが効果が高かったかはJubatusが勝手に判定してくれます。
その後はA/B/C/D/Eの中で効果が高いものを表示し始めます。
5.削除したいテンプレートが出てきた場合
Jubatusから削除します。
計測をやり直したい場合も、Jubatusから削除後登録するとリセットされます。
python delete_template.py
#!/usr/bin/env python
# coding: utf-8
host = '127.0.0.1'
port = 9199
name = 'A/B TEST'
import sys
import jubatus
from jubatus.common import Datum
def delete_arm(client, arm):
client.delete_arm(arm)
if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
if (argc != 2):
print 'Usage: # python %s templateName' % argvs[0]
quit()
template_name = argvs[1]
client = jubatus.Bandit(host, port, name)
delete_arm(client, template_name)
6.各テンプレートの点数を確認する場合
各テンプレートの表示回数と報酬の合計値を見ることができます。
#!/usr/bin/env python
# coding: utf-8
host = '127.0.0.1'
port = 9199
name = 'A/B TEST'
import sys
import jubatus
from jubatus.common import Datum
def get_arm_info(client, player):
return client.get_arm_info(player)
if __name__ == '__main__':
argvs = sys.argv
argc = len(argvs)
user_id = u'none'
client = jubatus.Bandit(host, port, name)
print get_arm_info(client, user_id)