モバイルアプリケーションの運営に欠かせない指標の1つであるユーザーリテンション、PartyTrack等の分析サービスを使っていると良く目にすると思う。ただ、自分の持っているデータでグラフを描画したいがWebフロントのJavaScriptは書きたくないというケースもある。
そんな時に見た次のエントリ
Making Pinterest — How Pinterest drives sustainable growth
http://engineering.pinterest.com/post/86533331849/how-pinterest-drives-sustainable-growth
コホートヒートマップが何かで描画されてる!! という訳で同じ見た目のグラフをPythonで描画してみる。
リテンション率のデータ
「ある日xに獲得したユーザーのy日後のアクティブ率z」を次の形で持っているとする。
{
"2014/08/16": [翌日の値],
"2014/08/15": [翌日の値, 2日後の値],
"2014/08/14": [翌日の値, 2日後の値, 3日後の値],
"2014/08/13": [翌日の値, 2日後の値, 3日後の値, 4日後の値],
...
}
グラフの描画
等高線をプロットするのと同じ要領でまずは獲得日x, 経過日数yのメッシュを作る。
from datetime import datetime
from matplotlib import dates
import numpy as np
vals = [
datetime(2014, 8, 16), [0.524],
datetime(2014, 8, 15), [0.574, 0.415],
datetime(2014, 8, 14), [0.559, 0.440, 0.355],
#略
]
# 表示する経過日数
max_y = 35
# xはdatetimeからnumberに変換しておく
x = map(lambda v: dates.date2num(v['date']), vals)
# yは1(翌日)からスタート
y = np.arange(1, max_y + 1)
# xとyのメッシュを作成
Y, X = np.meshgrid(y, x)
リテンション率の値がzとなるので、グリッドのyに配列の長さをあわせる。
def expand_z(v):
v = v['values']
v += list(np.zeros(max_y - len(v)))
return v
# 縦横を揃えるためにゼロ埋め配列を追加する
z = map(expand_z, vals)
# numpyの行列に変換する
Z = np.array(z).reshape(len(z), len(z[0]))
pcolorを使って疑似カラープロットを描画する。
import matplotlib.pyplot as plt
from matplotlib.ticker import MultipleLocator, FormatStrFormatter
fig, ax = plt.subplots(nrows=1, ncols=1, figsize=(8, 4))
# プロットの作成
# データによって色が変わってしまうのを回避するため、最大値を指定
im = ax.pcolor(X, Y, Z, vmax=0.6)
# タイトル
ax.set_title(u'Launch Retention')
# y軸
ax.set_ylabel(u'Past Days')
ax.set_ylim(bottom=1)
# x軸
ax.set_xlim(x[0], x[-1])
# カラーバー
plt.colorbar(im)
# Ticks
minorLocator = MultipleLocator(5)
ax.xaxis.set_minor_locator(dates.DayLocator())
ax.xaxis.set_minor_formatter(dates.DateFormatter('%d'))
ax.xaxis.set_major_locator(dates.MonthLocator())
ax.xaxis.set_major_formatter(dates.DateFormatter('%Y %b'))
ax.xaxis.set_tick_params(which='major', pad=17)
plt.xticks(rotation=0)
plt.show()
結果
できた。全体感を眺める用途には使えるだろう。?日後リテンションを指標として追うという場合は、別途その値だけ折れ線グラフか何かにすると経過を観察しやすい。どちらにしても、夜間バッチ処理で画像ファイルにしておけば、どこでも使えて便利。
今回のコードを手元で実行できる様にgistも用意しました、手元で動かしたい場合はこちらをどうぞ。
https://gist.github.com/hagino3000/455a68a79173fff1d890