概要
ログ解析サービスなどでよく見かけるこの図
コホート図と呼ばれ、Webサービス・アプリサービスに対するユーザーの継続率を確認することができます。
マーケティングの分野で主に使われ、
- 短期的なマーケティング施策の効果測定
- 特定のユーザー層のエンゲージメント測定
などミクロな視点でサービス状況を確認できます。
基本的に、GoogleAnalyticsやfirebaseアナリティクスなどマーケティングサービスの標準機能として付属していますが、
ユーザーのイベントログを多面的にチェックしようと思うと応用が効かず。
python(pandas)で集計しようと思いましたが、
あまり良さそうなリソースがなく、(あることはあるが、集計ミスが起きうる書き方をしている・・・)
1から手で書く上での基本的な手順をまとめてみました。
さっそく書いてみる
jupyter notebook
細かい説明はいらないからコードを見たいという方はこちらへ
https://github.com/pigooosuke/cohort_analysis/blob/master/kernel.ipynb
データ準備
手頃なオープンデータセットがあればいいのですが、
Webサービスのいい感じのユーザーログは公開されておらず、(かなり探したけれど見つからなかったです)
まずデータセットを作るところから始めます。
今回作るのはかなり簡易的なデータです。
- customer_id
- event_date (特定のログが記録された日付)
これを週次で観察してみます。
import random
from datetime import datetime, timedelta
def random_date(start, end):
"""startとendの差をday変換してランダムで選択して、startに加算"""
delta = end - start
int_delta = (delta.days)
random_day = random.randrange(int_delta)
return (start + timedelta(days=random_day)).strftime("%Y-%m-%d")
def random_id(n_size):
return random.choice(range(n_size))
def create_dataset(d_length, n_size, start_day, end_day):
""" datasetをつくる
customer_id: user
event_date: action(ログイン、特定のログなど、なにかしらの行動が発生した日)
weekofyear: event_dateがその年の何週目にあたるか
"""
d_list = []
for _ in range(d_length):
d_list.append([random_id(n_size),random_date(start_day, end_day)])
# dataframeに変換
df = pd.DataFrame(d_list, columns=["customer_id","event_date"])
# event_dateがその年の何週目にあたるのかを算出
df["weekofyear"] = pd.to_datetime(df["event_date"]).dt.weekofyear
return df
d1 = datetime.strptime('2018-01-01', '%Y-%m-%d')
d2 = datetime.strptime('2018-06-01', '%Y-%m-%d')
df = create_dataset(20000, n_size=1000, start_day=d1, end_day=d2)
df.head()
2018年1月から6月までで、
1000ユーザー分のログを2万件生成します。
併せて、そのイベント日が1年のうち何週目に当たるかを3列目に入れています。
集計作業
今回特定のイベントを行ったユーザーの継続率を確認するために、ユーザー単位でそれぞれ一番古いイベントの日付を特定します。
# merge
df=df.merge(df.groupby("customer_id")["event_date"].min().reset_index(),on="customer_id",suffixes=("","_init") ,how="left")
# 初回のイベント日についてもweekodyearを計算
df["weekofyear_init"] = pd.to_datetime(df["event_date_init"]).dt.weekofyear
df.head()
初回イベントに関しても何週目のイベントだったのかを確認します。
今回、特定期間から行動を始めたユーザーが各週でどう行動しているのかを確認しています。
そのため、マトリックスを作成し、それぞれに何ユーザー存在するかをカウントすればOKです。
gp = df.groupby(["weekofyear_init","weekofyear"])["customer_id"].nunique()
gp = gp.reset_index()
gp.head()
上記の2行目で言うと、1週に行動したユーザーのうち、2週目に行動したユーザー数が366人いたということがわかります。
図示していくためには、さらに工夫が必要で、そのweekofyear
はweekofyear_init
から数えて何週目に当たるのかを計算してみます。
# weekofyear_init(初回イベント発生日)から見て、それぞれのイベントが何周目後に発生したものかを集計
gp["cohort_group"] = gp["weekofyear"] - gp["weekofyear_init"] + 1
gp.head()
これをピボットテーブルに落としてみます。
user_retention=gp.pivot_table(values="customer_id",columns="cohort_group",index="weekofyear_init")
user_retention.head(20)
この表がまさにGAとかでよく目にするやつです。
ここの数字はユーザー数になっているので、1週目を元として比率に変換してみます。
# それぞれのイベント初日のユーザー数を取得し、各イベント期間にどれだけユーザーが残っていたのかを計算
user_retention = user_retention.apply(lambda x : x / x.iloc[0],axis=1)
user_retention.head()
最後にプロットしてみると
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(18, 6))
plt.title('Cohort Analysis: User Retention')
sns.heatmap(user_retention, mask=user_retention.isnull(), annot=True, fmt='.0%')
完成です。
今回は非常に簡易的な集計を行いましたが、
特定のユーザー層を元に、特定の行動を行っているのかを独自で集計したい場合はこのような形で集計しましょう。
参考