ABEMAでサーバーサイドエンジニアをやっている末松です。
メディア事業部の横軸組織PTAのアドベントカレンダーの12日目の記事となります。
はじめに
ABEMAでは、TV放送と同様の配信形態である リニア放送 と 好きな番組を好きな時間に見ることができる VOD があります。VODには有料コンテンツが含まれますが、無料コンテンツにはCMが流れています。
見ている視聴者に応じたCMを流したり、番組とマッチCMを流すために全員に同じCMを流したり、ケースバイケースでCMをコントロールしています。
そこで、今回は、CM効果を分析する上で、よく使っている 小技 をご紹介します。
tableauでフィルタの「すべて」は表示するべきか適宜考える
tableauでフィルタを設定したときに、デフォルトで「 (すべて) 」が表示されています。
例えば、「広告」、「自社広告」、「番宣」 それぞれで UU(ユニークユーザー)数を表示していた場合、(すべて) を選んだことで意図せず合算してしまう場合があります。
そのような誤解を回避するために、不適切な集計になる場合は (すべて) を下記のように、
「カスタマイズ」→ 「"すべて"の値を表示」 をOFFにします。
時系列で二次元のグラフを可視化
1次元追加する方法として、「色」や「形」があると思うのですが、日付自体をパラメータ化し、アニメーションによる変化もテクニックの一つかと思います。
下記の例では、CMを配信してから、FQ(CMを視聴した回数)別のUU(ユニークユーザー数)を表したものです。
初日、二日目、三日目と日が経つにつれて 接触回数1回 のユーザー数が顕著に増加していることがわかります。
ちなみに、接触回数7回が多くなっているのはFQキャップ(一人あたりに接触する最大回数)によるものです。デバイスやチャンネルによっては、FQキャップが効かない場合があるため、7回以上接触したユーザーが何人か存在しています。
日別でFQを表示する場合、日別の累積UUを求める必要があります。
tableau上でもWINDOW_MAX関数とWINDOW_SUM関数、FIRST関数を用いることで表現することができますが、今回は汎用的に使えるようSQLで表現しています。
tableau上で表現する場合は、こちらをご参考ください。
日別の累積UUをSQLで表現する方法
まずは、サンプルとなるデータを用意します。
WITH SAMPLEDATA AS (
SELECT *
FROM UNNEST([
STRUCT(DATE '2019-01-01' AS dt, 100 AS campaign_id, 'USER1' AS user_id),
(DATE '2019-01-02', 100, 'USER1'),
(DATE '2019-01-02', 100, 'USER2'),
(DATE '2019-01-03', 100, 'USER3'),
(DATE '2019-01-04', 200, 'USER1')
])
)
dt | campaign_id | user_id |
---|---|---|
2019-01-01 | 100 | USER1 |
2019-01-02 | 100 | USER1 |
2019-01-02 | 100 | USER2 |
2019-01-03 | 100 | USER3 |
2019-01-04 | 200 | USER1 |
次に、最終的にキャンペーン毎の接触回数を表現したいので、キャンペーン✕ユーザー単位で行番号を付与します。
SELECT
campaign_id,
dt,
user_id,
COUNT(1) AS imp,
ROW_NUMBER() OVER (PARTITION BY campaign_id,user_id ORDER BY dt) AS ROW_NUMBER
FROM SAMPLEDATA
GROUP BY dt,campaign_id,user_id
campaign_id | dt | user_id | imp | ROW_NUMBER |
---|---|---|---|---|
100 | 2019-01-01 | USER1 | 1 | 1 |
100 | 2019-01-02 | USER1 | 1 | 2 |
100 | 2019-01-02 | USER2 | 1 | 1 |
100 | 2019-01-03 | USER3 | 1 | 1 |
200 | 2019-01-04 | USER1 | 1 | 1 |
そして、次は、ROW_NUMBERが1となる日 = 初回接触日のみカウントするようにします
SELECT
campaign_id,
dt,
SUM(IF(ROW_NUMBER = 1, 1, 0)) AS FIRST_UU,
SUM(imp) AS imp
FROM (
/* ROW_NUMBERを付与したクエリ */
)
GROUP BY dt,campaign_id
campaign_id | dt | FIRST_UU | imp |
---|---|---|---|
100 | 2019-01-01 | 1 | 1 |
100 | 2019-01-02 | 1 | 2 |
100 | 2019-01-03 | 1 | 1 |
200 | 2019-01-04 | 1 | 1 |
これでこのユーザーを集約することができたため、後はSUM OVER関数を使ってキャンペーン毎のFIRST_UUの累積を求めれば日別の累積UUが算出されます。
SELECT
campaign_id,
dt,
SUM(FIRST_UU) OVER (PARTITION BY campaign_id ORDER BY dt) AS UU,
SUM(imp) OVER (PARTITION BY campaign_id ORDER BY dt) AS imp
campaign_id | dt | UU | imp |
---|---|---|---|
100 | 2019-01-01 | 1 | 1 |
100 | 2019-01-02 | 2 | 3 |
100 | 2019-01-03 | 3 | 4 |
200 | 2019-01-04 | 1 | 1 |
BigQuery上で確認できるクエリの全文はこちらです。
WITH SAMPLEDATA AS (
SELECT *
FROM UNNEST([
STRUCT(DATE '2019-01-01' AS dt, 100 AS campaign_id, 'USER1' AS user_id),
(DATE '2019-01-02', 100, 'USER1'),
(DATE '2019-01-02', 100, 'USER2'),
(DATE '2019-01-03', 100, 'USER3'),
(DATE '2019-01-04', 200, 'USER1')
])
)
SELECT
campaign_id,
dt,
SUM(FIRST_UU) OVER (PARTITION BY campaign_id ORDER BY dt) AS UU,
SUM(imp) OVER (PARTITION BY campaign_id ORDER BY dt) AS imp
FROM (
SELECT
campaign_id,
dt,
SUM(IF(ROW_NUMBER = 1, 1, 0)) AS FIRST_UU,
SUM(imp) AS imp
FROM (
SELECT
campaign_id,
dt,
user_id,
COUNT(1) AS imp,
ROW_NUMBER() OVER (PARTITION BY campaign_id,user_id ORDER BY dt) AS ROW_NUMBER
FROM SAMPLEDATA
GROUP BY dt,campaign_id,user_id
)
GROUP BY dt,campaign_id
)
ORDER BY campaign_id,dt