在 Day 17 與 Day 18 中,我們完成了 RFM 客戶價值金字塔,當時資料輪廓透露出一個令人不安的訊號:全平台有高達 96% 的買家終身只買過一次。
如果一位剛進公司的菜鳥分析師看到 GMV 逐月攀升,可能會興奮地向管理層回報:「平台正在快速增長!」
但身經百戰的高階主管與資深分析師只會冷靜地盯著另一個指標看——顧客留存率(Retention Rate)。
因為營收成長可能只是仰賴源源不絕的行銷預算買進新客;唯有留存率,能誠實反映出「產品與服務到底有沒有把買家留住」。
今天,我們將運用矽谷與頂級電商常用的 隊列分析(Cohort Analysis),以首購月份為基準切分族群,計算各批用戶在後續月份的生命週期變化,並用 Seaborn 繪製出資料分析領域最具視覺張力的「三角形留存熱力圖」,正面迎擊 Olist 平台最殘酷的商業真相!
做隊列分析的第一步,是幫每位獨立顧客標記他「第一次下單的年月份(Cohort Month)」。
初學者往往會先寫一次 groupby 取最小日期、再用 merge 拼回原表,程式碼冗長且耗損記憶體。資深分析師會直接使用 Pandas 的向量化利器 transform('min'),在不改變原表形狀的情況下,一鍵廣播首購時間:
import pandas as pd
import numpy as np
# 1. 複製包含顧客真實 ID 的有效訂單資料 (來自 Day 17 的 rfm_orders)
cohort_df = rfm_orders[['order_id', 'customer_unique_id', 'order_purchase_timestamp']].copy()
# 2. 將訂單下單時間轉為「年-月」的週期型態 (Period)
cohort_df['order_month'] = cohort_df['order_purchase_timestamp'].dt.to_period('M')
# 3. 核心技巧:利用 transform 取出每位用戶在歷史中的「最小月份 (首購月)」
cohort_df['cohort_month'] = cohort_df.groupby('customer_unique_id')['order_month'].transform('min')
# 檢視資料前三筆
cohort_df.head(3)
實作區:
有了「首購月份」與「當前訂單月份」,下一步就是計算相隔的時間跨度——隊列期數(Cohort Index):
# 1. 提取年份與月份的整數數值
order_year = cohort_df['order_month'].dt.year
order_month = cohort_df['order_month'].dt.month
cohort_year = cohort_df['cohort_month'].dt.year
cohort_month = cohort_df['cohort_month'].dt.month
# 2. 透過年月差值換算為相差月份數 (Cohort Index)
cohort_df['cohort_index'] = (order_year - cohort_year) * 12 + (order_month - cohort_month)
# 隨機檢視計算結果
cohort_df[['customer_unique_id', 'cohort_month', 'order_month', 'cohort_index']].sample(4, random_state=42)
有了隊列與期數,我們建立二維透視表(Pivot Table),統計每個隊列在各期數下的獨立活躍買家人數(nunique),並換算成百分比留存矩陣:
# 1. 建立人數透視表 (Index: 首購月, Columns: 隊列期數, Values: 獨立活躍人數)
cohort_pivot = cohort_df.pivot_table(
index='cohort_month',
columns='cohort_index',
values='customer_unique_id',
aggfunc='nunique'
)
# 2. 提取每組 Cohort 的初始新客規模 (即第 0 期的總人數)
cohort_sizes = cohort_pivot.iloc[:, 0]
# 3. 矩陣廣播除法:整張表除以第 0 欄,換算為留存率 (0.0 ~ 1.0)
retention_matrix = cohort_pivot.divide(cohort_sizes, axis=0)
# 4. 資料過濾:鎖定 2017 年 1 月至 2018 年 6 月營運成熟期,觀察前 12 個月的留存走勢
retention_matrix_filtered = retention_matrix.loc['2017-01':'2018-06', 0:12]
實作區 :

最後,我們使用 Seaborn 繪製留存分析中標誌性的三角形熱力圖。
專業作圖技巧:
由於 Olist 的留存率數值極低,如果色階上限設為 1.0(100%),整張圖除了第 0 欄外都會呈現死白一片。我們將色彩上限 vmax 定在 0.05(5%),以便敏銳捕捉低留存區間內的波動細節:
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(14, 8))
plt.title('Monthly Cohort Retention Analysis (Olist)', fontsize=14, fontweight='bold', pad=15)
# 繪製三角形熱力圖
sns.heatmap(
retention_matrix_filtered,
annot=True,
fmt='.1%',
cmap='YlGnBu',
vmin=0.0,
vmax=0.05, # 將色彩上限壓至 5%,以呈現細微漸層
cbar_kws={'label': 'Retention Rate'}
)
plt.xlabel('Cohort Index (Months After First Purchase)', fontsize=11, fontweight='bold')
plt.ylabel('First Purchase Cohort Month', fontsize=11, fontweight='bold')
plt.tight_layout()
plt.show()
實作區 :

看著這張熱力圖,任何對電商抱持「顧客會自然回購」幻想的人都會被狠狠敲醒。我們能梳理出三大核心商業洞察:
1.觸目驚心的「首月回購斷崖」:
無論哪一個月份進來的新客,到了 M+1(首購次月),留存率無一例外跌破 1%,平均落在 0.3%~0.6% 之間!意味著每花費行銷費用吸引 1,000 位新客人下單,下個月只會有不到 5 個人再次打開平台。
2.無生命週期曲線(Flat Line):
在健康的生活快消品電商中,留存曲線通常在第 3~6 個月逐漸平緩並形成一條穩定的水平基線(代表忠誠老客)。然而 Olist 的曲線幾乎是一落地就歸零,完全沒有展現出老客沉澱的體質。
3.平台戰略定位定性——「一次性採購站」:
結合前面分析過的品類結構(辦公家具、電子產品、手錶飾品),這張熱力圖給了平台清晰的定性:Olist 在本質上是一個以「新客獲取(Acquisition)」為單一引擎的撮合市集,絕非「高頻回購(Replenishment)」型電商。
4.營運資源投放的戰略轉移:
如果行銷團隊依然編列大筆預算去做「沈睡會員喚醒」或「長期回購刺激」,無異於把錢扔進水裡。最理性的商業策略,是把所有資源重押在「買家唯一願意下單的這一次結帳」上——極大化客單價、擴大購物籃!
今天我們攻克了衡量產品長期體質的終極指標:
掌握高效向量化運算: 透過 transform('min') 避免低效的合併迴圈,優雅衍生首購隊列標籤。
掌握留存矩陣換算: 熟練運用 pivot_table 與廣播除法,構建標準的隊列透視表。
透視平台營運本質: 藉由熱力圖戳破盲目經營回購的迷思,證實 Olist 是典型的一次性搜尋採購市集。
既然買家絕大部分一輩子只買這一次,那麼「如何讓他在這唯一一次的結帳中,把更多商品放進購物車?」就成為平台撬動利潤的唯一突破口!
明天 Day 20,我們將深入購物車內部——購物籃分析雛形(Market Basket Analysis):拆解訂單多品項關聯,挖掘交叉銷售(Cross-selling)與搭售黃金組合!