こんにちは、データ分析部の石塚 (@ij_spitz) です。 最近聴いている曲は久保田利伸さんのLA・LA・LA LOVE SONGです。 ロンバケ最高でした、月曜9時はOLが街から消えるというのも納得です。
Gunosyではプロダクト改善のためにABテストを用いて意思決定を行っています。 今回はタイトルにもある通り、ABテストを実現させる上で必要となる対象の割り振り方法を、Gunosyで以前使っていた従来の手法と半年ほど前に新しく導入した手法の2つをご紹介します。 いい感じってなんだよと思われるかもしれませんが、従来の手法の課題を解決するようにいい感じに割り振る方法と理解していただければと思います。 それぞれの運用上で気づいたメリット・デメリットなども合わせてご紹介します。
従来の手法
以前はユーザIDを100で割った余りを使用していました。 例えば、全ユーザの1%でテストしたいという時には、100で割った余り0を対象にしてテストを実施し、100で割った余り1と比較するという仕組みです。
LPなどのABテストでは1回切りの訪問のため、ユーザが複数回訪問してきたときに同じテストが割り当たることは考慮しなくてもいいですが、グノシーは毎日のようにユーザが継続して利用するニュースアプリなので、テスト期間中は同じユーザが同じテストに割り当たることが必須条件となります。 次にこの手法のメリットとデメリットを見ていきます。
メリット
- 集計がラク
- 標準SQLには
MOD
という剰余を計算する関数があるので、集計する際にはログが格納されているのがBigQueryでもRedshiftでも簡単に行うことができます。 - そのためログにユーザが割り当たっているABテストの情報を追加せずとも集計することができます。
- 標準SQLには
- 計算コストが気にならない
- 管理しやすい
- ユーザIDさえわかれば、どのユーザがどのABテストに割り当たっているかをすぐ確認できるので、管理しやすいです。
- Gunosyではスプレッドシートを使ってテストを管理していました。
- 弊社Go Engineerの azihsoyn さんの発表資料があるので、これを見るとどのように管理していたかイメージが伝わると思います。
- https://speakerdeck.com/azihsoyn/serverside-development-and-kaizen-with-golang
デメリット
- テスト対象を選ぶのが面倒
- この手法ではテスト対象と比較対象の2つを自分で選ぶ必要があります。
- テストの数が2個や3個だと対象を選ぶのも苦ではないのですが、10個や20個となってくると1ユーザに複数のテストを割り当てることになり、各テストが均等に割り当てられているかの担保が難しく、時間の掛かる作業となってしまいます。
- 以前のテストが影響してしまう
- 前に実施していたABテストがバイアスとなって効いてくる場合があります。
- あるテストを実施していた100で割った余りのユーザだけ数が少なくなっていたり、アクティビティの高いユーザ群になってしまい、誤った意思決定につながる可能性があります。
新しく導入した手法
現在使用している手法も余りを用いていますが、ハッシュ関数を利用したものになっています。 言葉で説明しても理解しづらいので、まずPythonのコードを載せます(Pythonのバージョンは3系を使用しています)。
import hashlib ratio = 5 key = 'ab_test_key' user_id = 4192481 mod = int(hashlib.sha1((key + str(user_id)).encode('utf-8')).hexdigest()[:15], 16) % 100 if mod < ratio: print('テスト対象') elif mod >= 100 - ratio: print('比較対象') else: print('どちらでもない')
- 割り当てアルゴリズムは以下のようになっています。
- ABテストごとに固有な文字列とユーザIDを連結
- 連結した文字列をハッシュ化して16進数の文字列に変換
- ハッシュ化した16進数の文字列の先頭15文字を取得する
- 先頭15文字を取得しているのはRedshiftで16進数を10進数に変換するときに、文字列が長すぎて桁あふれが起きてしまったため
- 取得した15文字を10進数に直す
- 最後に取得した数値の100で割った余りがテスト割合より小さければテスト対象として割り当てる
- 100からテスト割合を引いた値以上ならば比較対象として割り当てる
メリット
- テスト対象を選ぶのがラク
- 対象は自動で選ばれるのでかなりラクになりました。
- ただ1つ注意するポイントとしては、他のテストがテスト対象と比較対象に同じ割合で含まれている点です。同じ割合で含まれていれば比較する際には問題ないという仮定を置いているのですが、どうしてもこの2つのテストは被らせたくないという条件があれば、ABテストごとに設定する固有な文字列を同じにすると被らなくなります。
- 以前のテストが影響がなくなる
- この手法を用いると対象となるユーザはテストごとに変わるので、ずっと同じ対象でテストをし続けるといったことはなくなります。
デメリット
- 管理が複雑になる
- 以前のようにスプレッドシートだけで管理することはできなくなりましたが、テスト対象と比較対象をデータベースで管理しています。
- また、ABテストの拡大・停止のためのツールを作成しているので、管理コストはかなり抑えられていると思います。
- 集計が複雑になる
- 以前のようにSQLだけで集計を完結させることは難しくなりましたが、割り当たっているABテストの情報をログに付与したり、テーブルで管理することによって集計も手軽に実施することができます。
- ヒューマンエラーや手間を考えると集計は自動化することをおすすめします。
まとめ
今回新しく導入した手法で、テスト対象を選ぶ手間だったり、以前のテストが影響してしまうといった従来の手法による課題は解決することができました。 ただし、割り当てがブラックボックス化してしまい、本当に上手く行っているのかがわかりづらくなっているという欠点もあります。 そういったところをきちんと検証したいという場合には、A/AテストやGroup Validationといった仕組みを用いると誤った意思決定を減らすことができるので、興味があれば下記のリンクを参照してみてください。