23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pythonでコホート分析

Last updated at Posted at 2018-06-30

概要

ログ解析サービスなどでよく見かけるこの図
98860c727bd48664294de0efbf70dd72.png
コホート図と呼ばれ、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万件生成します。
3665e3095d54d6b6fb9a778c194a596a.png
併せて、そのイベント日が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()

b4cb71564b157783bbb55ee8ea910923.png
初回イベントに関しても何週目のイベントだったのかを確認します。

今回、特定期間から行動を始めたユーザーが各週でどう行動しているのかを確認しています。
そのため、マトリックスを作成し、それぞれに何ユーザー存在するかをカウントすればOKです。

gp = df.groupby(["weekofyear_init","weekofyear"])["customer_id"].nunique()
gp = gp.reset_index()
gp.head()

3e42774696f468e8e4c06b6bd3d2a247 (1).png

上記の2行目で言うと、1週に行動したユーザーのうち、2週目に行動したユーザー数が366人いたということがわかります。
図示していくためには、さらに工夫が必要で、そのweekofyearweekofyear_initから数えて何週目に当たるのかを計算してみます。

# weekofyear_init(初回イベント発生日)から見て、それぞれのイベントが何周目後に発生したものかを集計
gp["cohort_group"] = gp["weekofyear"] - gp["weekofyear_init"] + 1
gp.head()

96a1a6346cc0285cd135bc00671dc562.png

これをピボットテーブルに落としてみます。

user_retention=gp.pivot_table(values="customer_id",columns="cohort_group",index="weekofyear_init")
user_retention.head(20)

71a9ebf632e8c5d316171d29106e1161.png

この表がまさにGAとかでよく目にするやつです。
ここの数字はユーザー数になっているので、1週目を元として比率に変換してみます。

# それぞれのイベント初日のユーザー数を取得し、各イベント期間にどれだけユーザーが残っていたのかを計算
user_retention = user_retention.apply(lambda x : x / x.iloc[0],axis=1)
user_retention.head()

321b11724bebe0ba1e539f87faf400d7.png

最後にプロットしてみると

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%')

40f06b0f4b76a8f9fc6e3f066f77d915.png

完成です。
今回は非常に簡易的な集計を行いましたが、
特定のユーザー層を元に、特定の行動を行っているのかを独自で集計したい場合はこのような形で集計しましょう。

参考

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?