※ こちらはミツモアAdvent Calendar 2022の19日目の記事です。今年も昨年に引き続きアドベントカレンダーをやってます。昨年の記事については ミツモアAdvent Calendar 2021 こちらを見てみてください。
こんにちは、ミツモア データチームの古田(@crazysrot)です。今回はミツモアでテレビCMを実施した際に行なった効果検証をについて紹介します。
背景
ミツモアでは、2022年に入ってから断続的にテレビCMを実施しています。その際に「CM効果を認知やサイト来訪といった指標だけでなく、より事業の数字に近いKPIで見られるようにしたい!」という要望が上がりました。
ミツモアでは、効果のtargetを依頼作成数として分析しました。依頼内容の回答や個人情報の入力が完了したタイミングのこと。各企業によっては各々に設定してあるKPIに従ってこれがPV/セッション/商品購入などの設定をします。
手を動かす前に事前に考えたこと
アルゴリズムについて
本来CMの効果検証というのは外部要因がとても多く、厳密に分析を実施するとなるとMMM(Marketing Mix Modeling)のようなとても複雑な分析が必要になると言われています。多数のチャネルがあり、かなりブランドを築けている会社においてはMMMのような手法を用いる方が良いかもしれませんが、今回はそこまで複雑にせずシンプルなモデルを作成することにしました。下記がそうした理由になります。
- PVが大きく上昇するような影響が出ると期待されていた
- 過去にCMを継続的に実施していない
- チャネルがある程度限られており、別チャネルの設定を大きく変更しない
分析環境から可視化まで
全て、Colaboratory上で完結することにしました。理由は次の二つです。
- データ分析基盤全体をGCP上に構築しており、Colaboratoryだとデータ連携がしやすい。BigQueryやGCSのデータ連携で認証が通しやすい
- Colaboratoryのノートブックの先頭にパラメータを定義すれば、非エンジニアでも各自で実行する運用方法が可能になる
後述しますが、今回のケースにColaboratoryを選択したことは失敗でした…
効果検証分析
アルゴリズム
ミツモアでは成長し続けているサービスなので、過去に時系列分析を積極的に行なっていませんでした。そのため、それに対する経験が乏しかったため、複数の時系列分析を簡易的に実施できるDartsを用いました。Dartsは各種時系列モデルをwrapperしたライブラリで、中ではstatsmodels
, Prophet(stan)
, Pytorch
などを利用しています。これらのアルゴリズムを多数検証し、どの要素(季節要因など)を取り込む必要があるのかなどの確認も行いたい意図もありました。
特徴量エンジニアリング(Feature Engineering)
都道府県とサービス別で依頼数をdailyで集約して特徴量としました。
集約単位をdailyにした根拠は、サンプル数を増やしたいのと、分析結果の利用はdailyが最小単位になりそうだったためです。
都道府県別で集約しているのは、基本的にCMの放映が都道府県別に行われている仮定を置いて分析をしたかったからです。サービス別で集約しているのは、CMで直接訴求するサービスがミツモアブランドではなく特定サービスであったため、直接訴求したサービスの効果検証も実施したかったためです。また、今回訴求したサービスがエアコン系のものが多かったため、普及率の低い北海道は除外して分析をした結果も確認してみる必要があったので、こちらの対応は必須でした。
また、別チャネルの広告宣伝費用のデータの使用も検討しましたが、結局これは行いませんでした。今回は少ない工数で作成したかったことと、サンプル数不足に陥る可能性が高いなどの理由によりシンプルにモデルを作成する必要があったためです。
実際に作成したコードのサンプル
実際に分析に使用したコードを、サンプルデータを使用して説明してきます。以下の前提でコードのサンプルを提示していきます。
- 2020-01-01~2020-04-30 の期間のCV数のデータを利用する
- 都道府県は pref1, pref2, pref3 の三つの都道府県とする
- 2020-04-01~2020-04-30 の期間に pref1 でCMを放映している。pref2, pref3 ではCMの放映はしていない
- pref1 で放映したCMの効果を検証する
ここでは精度検証などの話は省略して、ライブラリの使用方法とCM効果検証の大まかな流れに焦点を当てます。
Datsのインストール
pipで入れます。
pip install darts
ダミーデータの準備
データは県別のdailyのCV数とします。値はなんでも良いので乱数で作成します。
import pandas as pd import numpy as np rng = np.random.default_rng(12345) start = pd.Timestamp("2020-01-01") end = pd.Timestamp("2020-04-30") size = (end - start).days + 1 df = pd.DataFrame( { "date": pd.date_range(start, end), "pref1": rng.integers(low=0, high=10, size=size), "pref2": rng.integers(low=0, high=10, size=size), "pref3": rng.integers(low=0, high=10, size=size), } )
DartsのTimeseriesオブジェクトの作成
Dartsの学習を行うため、pandas.DataFrameからdarts.TimeSeriesに変換します。この際CMの対象県か否かでデータを分けます。CM対象県のデータは、CM放映前と放映後でデータを分けます。
from darts import TimeSeries cm_start = pd.Timestamp("2020-04-01") # CM対象県(pref1)のデータ series = TimeSeries.from_dataframe(df, time_col="date", value_cols="pref1") # CM非対象県(pref2, pref3)のデータ covariable = TimeSeries.from_dataframe(df, time_col="date", value_cols=["pref2", "pref3"]) # CM対象県のCM放映期間(2020-01-01~2020-03-31)のデータ train = series.slice(start_ts=start, end_ts=cm_start - pd.Timedelta(1, "d")) # CM対象県のCM放映期間(2020-04-01~2020-04-30)のデータ valid = series.slice(start_ts=cm_start, end_ts=end)
モデル作成
dartsには多くの時系列モデリングライブラリがラップされていますが、その中でもprophetを使用してモデルを作成します。
from darts.models import Prophet model = Prophet() model.fit(train, future_covariates=covariable)
予測値算出、効果検証
作成した機械学習モデルを使用して、CM対象県のCM放映期間における、仮にCMを放映していなかった世界でのCV数を予測します。その値と、CMの影響が現れている実際のCV数を比較して、CMの効果とします。
n = (end - cm_start).days + 1 pred = model.predict(n, future_covariates=covariable) # 実際のpref1のCV数 (CMの効果が反映されている) cv_true = valid.sum(axis=0).values().item() # 予測のpref1のCV数 (CMの効果が反映されていない) cv_pred = pred.slice(start_ts=cm_start, end_ts=end).sum(axis=0).values().item() # 二つのCV数の差を比較して、CM効果とする。 cv_true - cv_pred
Colaboratoryにして後悔した話
本題です
Colaboratoryとは
Colaboratoryについて何かしらご存知の方であれば当然の話ですが、ColaboratoryはいわゆるSaaS型Jupyter Notebookで、とても便利なサービスです。あらかじめ分析に必要な各種ライブラリがプリインストールされている、裏で常にアップデートが走っており常に最新に近い状態になっている、再実行するだけならばGoogleDrive上で非エンジニアでもクリックのみで簡単に実行できる、といったことが強みとしてあります。
Colaboratoryであるが故にエラーが発生してしまう
しかし、今回は「裏で常にアップデートが走っており常に最新に近い状態になっている」部分が逆にデメリットになってしまい、とても後悔してしまいました。
ミツモアでは長期に渡りCMを実施しました。そのため、プログラムを使い回して実行する期間が6ヶ月以上もあり、Colaboratoryの裏で何かしらのアップデートが行われるたびに pip install 時に発生するエラーが発生することが多発していました。
上述したように、今回アルゴリズムにはDartsを利用しました。Dartsは、Wrapper libraryのため、さまざまな箇所でコンフリクションエラーが発生しやすかったのではないかと考えています。なので、同様のライブラリを使用するときは今後は慎重に選択したいと思います。似たようなwrapperライブラリである、PyCaretなども同じようなエラーが出るケースがあるようです。
臨時のエラー回避方法例
コンフリクトを起こしているライブラリをVersion指定して pip install したり、先に不要なものをuninstall してから実行したりしました。
# Sample for error avoidance !pip uninstall -y imgaug fbprophet # Uninstall first !pip install pyyaml==5.4.1 # https://github.com/unit8co/darts/issues/897 !pip install darts==0.22.0 # Select specify version
今回のケースでは、Prophet 周りでの error が多かったように記憶しています。
今後のColaboratory使用方針
今回のColaboratory使用での経験を振り返ると、実装前に以下の観点をもっと慎重に考慮するべきだったと思っています。これらの観点から、今後はColaboratoryだけではなく、GCPの各種サービス(Vertex AIやCloud RunやCloud Functionsなど)を使用して、開発効率を上げていきたいと思っています。
使用するライブラリの依存性の複雑さ
今回使用したDartsは多数の時系列モデリングライブラリをwrapしたパッケージであるため、必然的に他のライブラリへの依存関係が複雑になります。このような場合、Colaboratoryだとプリインストールされているライブラリとのバージョンのコンフリクトが発生してしまい、version指定などで色々悩まされることになります。
ソースコード量のスケール
Colaboratoryだと一つのノートブックに全てコードを書き切らないといけないので、プログラムが複雑になり肥大化していくにつれ、運用、保守、開発が加速度的に難しくなっていきます。今回のCM効果検証のプログラムでは、ソースコードはほとんど.py
ファイルに書き、それをGoogleDriveに置き、GoogleDriveをマウントしてノートブックの方からimport
して使用していましたが、これもあまり良い方法ではありませんでした。理由は、GoogleDriveへのソースコードの配置の自動化が難しいこと、またGoogleDriveをフォルダごとコピーしてしまい少しだけ変更が加えられたソースコードが複数のディレクトリに分散し収集が付かなくなることなどがありました。
プログラム利用期間のスケール
プログラムの利用期間が長いと、その間にColaboratory側でライブラリのバージョンアップや、Dartsなどの新たにインストールしているライブラリでバージョンアップがあったりします。このバージョンアップがある度に、コンフリクトを解消する作業をしないといけないので、かなり保守に工数がかかるようになります。
最後に
今回は、テレビCM分析の取り組みを失敗談も含めて紹介いたしました。 とてもシンプルなモデル作成をしましたが、今後さらにサービスが成長してくると、より高度化した分析を実施する必要が出てくるため、今回とはまた違ったアプローチをとった分析にする必要があると思っています。もちろん、その際は今回の反省を活かしてColaboratory以外の環境を選択することになるでしょうw データチームは、日本のGDP向上のため、よりビジネスに直結する正確な分析結果を素早く提供できるように今後も引き続き改善を続けていきます。
ミツモアでは様々な職種のエンジニアを積極的に採用しています! ご興味がある方はぜひ気軽に面談しましょう!