なにこれ
どのアクションで離脱しやすいか・思ったような行動をユーザーがしてくれているかを把握するために、アプリ内のユーザーの遷移状態・行動フローを可視化したいです。
今回はその手段として、PlotlyのSankeyDiagramを使おうと思います。
コードはCollaboratoryにまとめてあります。
https://drive.google.com/open?id=1ilGnpeOv7y49xBrQ5I0lrHNaT5H_tY6w
SankeyDiagramとは
サンキー・ダイアグラム(英Sankey diagram)は工程間の流量を表現する図表である。
サンキー ダイアグラム - Wikipedia
「アクションというノード」と「アクション間を遷移するユーザー数というリンク」で構成されたネットワークを可視化するのに使えそうです。
使ってみる
Plotlyに渡すためのデータ
リンク情報として、どのノードから(source)どのノードへ(target)どのくらいの量(value)を渡します。
ノード番号はindex番号として渡すため、例えばノード0からノード1へ100のvalue, ノード1からノード2へ50のvalueだとすると、以下のように渡します。
source = [0, 1] target = [1, 2] value = [100, 50]
集計の方法にもよりますが、今回は ユーザー毎にアクションした時刻が項目として横に広がるデータ を出発点とします。
そこからPlotlyに渡せるようデータを加工します。
セッティング
必要なライブラリをインポートします。
import numpy as np import pandas as pd import plotly from IPython.display import HTML
テストデータ
df = pd.DataFrame({ 'user_id': list(range(8)), '登録': pd.Timestamp('20190101'), 'アクションA': [pd.Timestamp('20190103') for _ in range(5)] + [pd.NaT] * 3, 'アクションB': [pd.Timestamp('20190105') for _ in range(2)] + [pd.NaT] * 6, 'アクションC': [pd.NaT] * 5 + [pd.Timestamp('20190110') for _ in range(3)] })
- 登録 -> A -> B が2人
- 登録 -> A が3人
- 登録 -> C が3人
となるような図ができあがるはずです。
データ加工
「user_id, アクション1, アクション2, ...」となっているデータを「user_id, アクション名, アクション時刻」とuser_id毎にアクション時刻でソートするように変換し、user_id毎にアクションのラグを取ります。
# user_id, アクション名, アクション時刻 というDataFrameに変換 lag_df = df.set_index('user_id').stack().reset_index().sort_values(by=['user_id', 0]) # ラグをとる lag_df['after_level_1'] = lag_df.groupby('user_id')['level_1'].shift(-1)
こうすることで、1行毎にアクションからアクションへのリンクがわかるデータになるので、それを集計します。
# edgesディクトの初期化 edges = dict.fromkeys(lag_df['level_1'].drop_duplicates().values, {}) for k in edges: edges[k] = dict.fromkeys(lag_df['level_1'].drop_duplicates().values, 0) # その後の行動がない行を除いて集計 for v in lag_df[~lag_df['after_level_1'].isnull()].values: edges[v[1]][v[3]] += 1 pd.DataFrame(edges).T
Plotlyに渡せるようなリストを作成します。
labels = list(edges.keys()) sources = [] targets = [] values = [] # labelsにアクション名リストを作成し、そのindex番号をsourcesとtargetsに入れる for src in edges: for tgt, v in edges[src].items(): sources.append(labels.index(src)) targets.append(labels.index(tgt)) values.append(v)
PlotlyのSankeyDiagramで可視化
data = dict( type='sankey', node = dict( label = labels ), link = dict( source = sources, target = targets, value = values )) layout = dict( title = "行動フロー", font = dict( size = 20 ) ) fig = dict(data=[data], layout=layout) plotly.offline.plot(fig, validate=False) HTML('temp-plot.html')
いい感じに可視化されました(^ ^)
そのほかのライブラリとして
「d3-sankey-diagram」というjavascriptのライブラリを用いることでSankeyDiagramを作成可能です。
Pythonで扱うためのrapperとしてricklupton/ipysankeywidgetが個人開発されており、当初はこちらを使っていたのですが、Issueで報告されている通り、Layoutのカスタマイズに難があったり、Collaboratoryでの可視化ができません。
データの渡し方的にはこちらの方が好みだったのですが、やむなくPlotlyの方を使いました。