透過上次 RFM 用戶分析模型將訪客分群,用 Python繪出桑基圖(Sankey)將用戶不同時間點分群的變化,用來觀察整體訪客經營是否符合預期中的變化。

桑基圖 (Sankey Diagram)

桑基圖是一種流程圖,其資訊包含著流量的大小、方向及變化狀況,套用在不同階段的客戶分群上,可以簡單看出訪客的變化狀況。

客戶分群意義

接續 RFM 用戶分析模型的分組,避免維度太多只使用 Frequency 與 Monetary 分成 4 組。

Frequency 頻率Monetary 金額客戶分群
Best Customers
Value Customers
Loyal Customers
Cheap Customers

實作

分群步驟參照前一篇 RFM 用戶分析模型

資料準備

Sankey 圖基本上由 source, target, value 組成,其資訊包含著流動方向與流量值。下圖為這次準備的數據集,其包含客戶每半年的分群與數量。

繪圖

函數

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
def gen_sankey(df, cat_cols=[], value_cols='', title='Sankey Diagram'):
""" 生成 Sankey fig 物件

:param df: 資料 DataFrame
:param cat_cols: 流程中的級別欄位名稱
:param value_cols: 每個流程的數量欄位名稱
:param title: Sankey 標題名稱
:return: dict() sankey data
"""
# 漸層色
colorPalette = ['#3f51b1', '#5a55ae', '#7b5fac', '#8f6aae', '#a86aa4', '#cc6b8e', '#f18271', '#f3a469', '#f7c978']
labelList = []
colorNumList = []
for catCol in cat_cols:
labelListTemp = list(df[catCol].unique())
colorNumList.append(len(labelListTemp))
labelList.extend(labelListTemp)

# labelList 去除重複
labelList = list(dict.fromkeys(labelList))

# 根據層級定義顏色
colorList = []
for idx, colorNum in enumerate(colorNumList):
colorList = colorList + [colorPalette[idx]]*colorNum

# DataFrame 轉換成 source -> target
sourceTargetDf = pd.DataFrame(columns=['source', 'target', 'count'])
for i in range(len(cat_cols)-1):
tempDf = df[[cat_cols[i], cat_cols[i+1], value_cols]]
tempDf.columns = ['source', 'target', 'count']
sourceTargetDf = pd.concat([sourceTargetDf, tempDf])
sourceTargetDf = sourceTargetDf.groupby(['source', 'target']).agg({'count': 'sum'}).reset_index()

# 對 source-target 編譯成 index
sourceTargetDf['sourceID'] = sourceTargetDf['source'].apply(lambda x: labelList.index(x))
sourceTargetDf['targetID'] = sourceTargetDf['target'].apply(lambda x: labelList.index(x))

# 建立 Sankey 圖
data = dict(
type='sankey',
node = dict(
pad = 15,
thickness = 20,
line = dict(
color = "black",
width = 0.5
),
label = labelList,
color = colorList
),
link = dict(
source = sourceTargetDf['sourceID'],
target = sourceTargetDf['targetID'],
value = sourceTargetDf['count']
)
)

layout = dict(
title = title,
font = dict(
size = 10
)
)

fig = dict(data=[data], layout=layout)
return fig

函式使用

python
1
2
3
4
5
6
7
8
9
10
import plotly
import plotly.graph_objects as go

fig = genSankey(rfm_variety, cat_cols=[
'level_201701', 'level_201706', 'level_201801',
'level_201806', 'level_201901', 'level_201906'
], value_cols='count', title='訪客生命週期可視化')

# plotly.offline.plot(fig, validate=False) ## 生成 html
go.Figure(fig) ## 繪圖