iT邦幫忙

2026 iThome 鐵人賽

DAY 11
0
Build on Google AI

AI-Driven MarTech:用 Google Cloud + Vertex AI 打造全自動廣告歸因與多模態素材分析系統系列 第 11 篇

Day 11 | 讓資料自己分組,才發現你的顧客其實只有這幾種人

  • 分享至 

  • xImage
  •  

1. 前言:同為舊客,行為特徵與回購週期卻大相徑庭

行銷報表最常見的切法是新客和舊客,但同樣是舊客,有人隔一陣子就回來、有人一次買很多就沒再出現、有人只試買過一次,這幾種人該收到的訊息、該花的廣告預算都不一樣,用新舊二分法全部混在一起看就看不出差別。

要把顧客分得更細,常見的做法是行銷人員自己訂規則,例如買兩次以上算忠誠客、客單價超過一千元算高價值客,規則好懂但門檻是人訂的,訂錯了也不會有人發現,今天換個方向,先把每位顧客的購買行為整理成一列數字,交給 BigQuery ML 的 K-means 讓資料自己分組,再回頭看每一組是什麼樣的人。

Day 05 的合成器在資料裡藏了四種顧客類型,今天分群時完全不看答案,等分完之後才揭曉,看 K-means 分出來的群和藏進去的類型對不對得上,今天的雲端費用都以 1 美元約 32 元換算成新台幣。

今日核心目標:

  1. 把每位顧客整理成一列 10 個購買行為特徵,用首購後觀察滿 30 天的 1,458 人訓練
  2. 用 BigQuery ML 建 K-means 模型分成 4 群,看每一群的訂單數、回購率、營收和偏好的商品
  3. 揭曉答案表,找出哪幾種顧客分得出來、哪一種分不出來,以及剛下單的新顧客為什麼容易被分錯

2. 系統架構全景與設計理念

圖一:訂單整理成每位顧客一列特徵,K-means 依特徵分成 4 群寫進 mart_customer_segment,答案表放在另一個資料集,只有揭曉時才會讀到

步驟 做什麼 產出
整理特徵 從 Day 07 的 fct_orders 把每位顧客的訂單彙總成一列 seg_features,2,461 人,其中觀察滿 30 天的 1,458 人
建模型 用觀察滿 30 天的人訓練 K-means,分成 4 群 seg_kmeans_k4
分群 每位顧客依特徵分到最近的群 mart_customer_segment,一位顧客一列
看輪廓 每一群的人數、訂單數、回購率、營收、品類占比 分群輪廓表
揭曉 分群結果和答案表對照 對照表

💡 核心工程理念:

  1. 答案和分析分開放:答案表放在獨立的資料集 martech_gt,分析與訓練只讀 martech_dw,只要看 SQL 裡有沒有出現 martech_gt 就知道有沒有偷看答案
  2. 分群數先定再看答案:分幾群用指標和用途決定,揭曉之後就算發現別的分法比較準,正式結果也不回頭改
  3. 分群結果要落表:寫進 mart_customer_segment,之後的驗收和 AI 查資料庫都會用到

3. 核心技術深度拆解

3.1 把每位顧客變成一列數字

K-means 只看數字,所以第一步是替每位顧客挑出能描述購買行為的欄位,機器學習裡稱為特徵,我挑了 10 個:

特徵 說明
訂單數、總件數、總營收 買了幾次、幾件、多少錢
首購件數 第一次下單買了幾件
襪子、浴巾、洗臉巾、組合四個品類的件數占比 買的都是什麼,四個加起來是 1
平均回購間隔 兩次下單之間平均隔幾天
距今天數 最後一次下單到資料最後一天隔了幾天

縣市和通路先不放,今天只看買了什麼、怎麼買,特徵的 SQL 在 segmentation/features.sql。

整理時有兩個細節會直接影響分群結果,第一個是只買過一次的人沒有回購間隔,這個欄位如果留空,BigQuery ML 會用全體平均值補上,沒回購的人就會看起來像平均隔一段時間就回來一次,所以我改填「首購到現在已經等了幾天」,意思是至少隔這麼久還沒回來。

第二個是各特徵的單位差很多,總營收從幾百到上千元、訂單數多半是 1 或 2、品類占比介於 0 到 1,K-means 用距離判斷誰跟誰比較像,不先處理的話營收差一百元的影響會遠大於訂單數差一次,BigQuery ML 預設會把每個特徵標準化,也就是換算成「高於或低於平均幾個標準差」,讓每個特徵放在同一個尺度上比較。

訓練只用首購後觀察滿 30 天的人,資料最後一天是 9/16,也就是首購在 8/17(含)以前的 1,458 人,這些人已經有足夠時間顯現會不會回購,群的樣子由他們決定,最近才第一次下單的人一樣會分到最近的群,但另外標記,3.4 會說明原因。

3.2 讓 K-means 自己分群

K-means 的做法是先放下幾個群中心,把每位顧客分給最近的中心,再把中心移到這群人的平均位置,一直重複到中心幾乎不再移動為止,BigQuery ML 裡只要一段 CREATE MODEL:

CREATE OR REPLACE MODEL martech_dw.seg_kmeans_k4
OPTIONS(
  model_type = 'KMEANS',
  num_clusters = 4,
  kmeans_init_method = 'KMEANS++',
  standardize_features = TRUE
) AS
SELECT order_count, total_qty, total_revenue, first_qty,
       share_sock, share_bath, share_face, share_set,
       avg_gap_days, recency_days
FROM martech_dw.seg_features
WHERE observed_30d;

kmeans_init_method 預設是隨機放中心,每次建模型結果可能差很多,改成 KMEANS++ 會讓一開始的中心彼此拉開,結果比較穩定但仍有隨機成分,這個模型重複了 3 輪中心就幾乎不動了。

分幾群要自己決定,我先定好分群的用途是「依顧客常買的品類推送不同商品訊息」,再建了 3、4、5 群三個模型,用 ML.EVALUATE 看 Davies-Bouldin 指標,這個指標衡量群內夠不夠緊、群和群之間夠不夠開,越小越好:

分幾群 Davies-Bouldin
3 群 1.480
4 群 1.058
5 群 1.365

4 群的指標最好,所以正式結果用 4 群,接著用 ML.PREDICT 把每位顧客分到最近的群,再算出每一群的輪廓,這張表還沒有看答案,是行銷人員替每一群取名字的依據,回購率是下單兩次以上的人占比,主要品類是群內平均的件數占比:

群 人數 平均訂單數 回購率 首購件數 平均營收 主要品類(件數占比)
1 286 1.07 6.6% 1.08 976 元 組合 97%
2 100 1.12 11.0% 1.30 408 元 洗臉巾 96%
3 262 1.12 10.7% 2.44 1,741 元 浴巾 97%
4 810 1.90 54.9% 1.49 675 元 襪子 96%

光看這張表就能替四群取名字:組合客、洗臉巾客、浴巾客、襪子客,其中襪子客人數最多、回購率超過五成,浴巾客首購平均買 2.44 件、營收最高但很少回來,K-means 分出來的四群是依「買什麼」分的,10 個特徵裡有 4 個是品類占比,而且大多數人幾乎只買一種品類,品類就成了最明顯的分界,群的編號本身沒有意義,重建模型時可能對調,要看輪廓來認群。

發文前我照第 5 章的步驟重跑一次,同一份特徵重建 4 群模型,分出來的卻是另一種樣子,浴巾客一樣自成一群,但襪子客改依有沒有回購拆成兩群、組合客和洗臉巾客併成一群,Davies-Bouldin 是 1.235,比上面那次差,KMEANS++ 只是讓起點比較分散,仍然帶有隨機成分,而這份資料不只一種說得通的分法,每次重建都可能落在其中一種,所以本文以揭曉前決定的那一次為正式結果,讀者自己跑出來的群和文章不同是正常的,要看輪廓判斷每一群是什麼人。

3.3 揭曉答案表

合成器藏進去的四種顧客是高頻買襪客、浴巾大量客、新手組合客和沉睡客,沉睡客買完第一次就不會再回來,買什麼則是跟著當時的活動隨機決定,分群流程裡只有揭曉用的兩份 SQL 會讀答案表,下表只統計觀察滿 30 天的 1,458 人:

群 高頻買襪客 浴巾大量客 新手組合客 沉睡客
1 組合客 0 0 200 86
2 洗臉巾客 0 0 11 89
3 浴巾客 0 191 0 71
4 襪子客 474 0 64 272

reveal.sql 印出的欄位是英文,依序是 sock_regular、bath_bulk、starter_new、dormant。

浴巾大量客 191 人全部在群 3,高頻買襪客 474 人全部在群 4,這兩種人各自集中在一群,但那兩群都混進了沉睡客,群 3 有 71 人、群 4 有 272 人,群 4 的 810 人裡真正的高頻買襪客只占 58.5%,新手組合客有 200 人在群 1,另外 64 人在群 4、11 人在群 2,對得上的比例約七成三。

分不出來的是沉睡客,518 人散在四個群裡,而且每一群都有,沉睡客第一次買什麼是隨機的,買襪子的就和高頻買襪客一起進了群 4,買浴巾的就進了群 3,差別只在後來有沒有回來,但 4 群的分法是依品類分的,沉睡客就被併進各自買過的品類。

換成 5 群就不一樣了,同樣的特徵分 5 群時,有一群 436 人平均只下單 1 次、主要買襪子和洗臉巾,518 位沉睡客有 359 人在這一群,另外還有一群 210 人平均下單 3.24 次,其中 206 人是高頻買襪客,5 群比較接近藏進去的類型,但它的 Davies-Bouldin 是 1.365,比 4 群差。

也就是說指標最好的分法,不一定最接近真實的顧客類型,但我在揭曉前就決定用 4 群,正式結果不因為看到答案而改成 5 群,看完答案才換分法等於事後調整判準,分數當然會變好看,實際工作沒有答案表可以對,這種做法就沒有意義了,Day 13 會用同樣的原則替所有找回的訊號打分數。

3.4 剛下單的新顧客容易被分錯

資料最後 30 天才第一次下單的有 1,003 人,這些人很容易被分錯,今天試了兩種訓練方式結果都一樣,只用觀察滿 30 天的人訓練的 5 群模型,把其中 594 人分進平均下單 1.92 次、以襪子為主的那一群,裡面有 248 人是沉睡客,我另外用全部 2,461 人訓練了一個 4 群的模型當對照,也把其中 513 人分進「回購襪子」群,裡面 334 人確實是高頻買襪客,但有 176 人是沉睡客。

從特徵來看,這些人剛下單不久,距今天數很小,回購間隔補的是「已經等了幾天」,數字也很小,兩個數字加起來就像常常回來的人,其實只是還沒到看得出會不會回來的時間點。

換了訓練資料也沒有改善,所以最實際的做法是新顧客照樣分到最近的群,但另外標記「觀察未滿 30 天」,mart_customer_segment 保留了 observed_30d 欄位,看報表或下廣告名單時先把這些人排除,等觀察滿 30 天後重跑 features.sql 更新特徵,再用同一個模型跑 predict.sql 重新分群就好,不需要重新訓練。


4. FinOps 成本防護實踐:三道防線體系

  1. 第一道防線:善用 Google Cloud 每月免費額度:ML.PREDICT、ML.EVALUATE、ML.CENTROIDS 和一般查詢一樣含在每月 1 TiB(約 1 兆位元組)的免費額度內,但 CREATE MODEL 不在免費額度裡,K-means 建模型每 TiB 312.5 美元,是一般查詢的 50 倍
  2. 第二道防線:架構層被動成本防護:先把特徵存成一張 2,461 列的小表,建模型時只讀這張表,實際處理約 0.2 MB,照每個查詢最低 10 MB 計費,每個模型約新台幣 0.1 元,我原本擔心重複幾輪就收幾次錢,查了 BigQuery 記錄每個工作計費量的系統表 INFORMATION_SCHEMA.JOBS,確認每個模型只收一次 10 MB,今天建了 4 個模型共約新台幣 0.4 元
  3. 第三道防線:Cloud Billing 預算警報:沿用 Day 03 由 Terraform 建立的預算警報(新台幣帳戶 NT$ 300/美元帳戶 US$ 10),50%、80%、100% 三段通知,今天的操作不會觸發

特徵表實際只處理 0.2 MB,就算顧客多到 50 倍,建一個模型也還在最低 10 MB 的計費範圍內,先彙總成一人一列再訓練,是 BigQuery ML 最直接的省錢方法。


5. Cloud Shell 實戰演練:一行指令分群並揭曉

5.1 事前準備

  • 已完成 Day 07,martech_dw 裡有 fct_orders
  • Cloud Shell 裡跑過 Day 05 的合成器,synthesizer/out/ground_truth/ 裡有答案檔,沒有的話用固定種子重跑一次會得到同一份
  • 確認 gcloud 有登入中的帳號,輸入 gcloud auth list,帳號前面要有星號

5.2 路線 A|懶人包:一行指令從特徵到揭曉

cd ~/ai-driven-martech-pipeline && git pull && bash segmentation/run.sh

畫面印出預估費用後輸入 yes,看到檢查項目全部通過、分群輪廓表與揭曉對照表就完成了,run.sh 只建正式的 4 群模型,想重現 3 群、5 群與全部顧客的對照,加上 --compare 會多建 3 個模型,約多花新台幣 0.3 元。

5.3 路線 B|逐步教學:理解每一個步驟

步驟 1:載入答案表

cd ~/ai-driven-martech-pipeline
git pull
bash scripts/load_ground_truth.sh

會建立資料集 martech_gt,載入顧客類型 2,461 列與訊號說明 7 列,載入不收費。

步驟 2:整理特徵

bq query --nouse_legacy_sql < segmentation/features.sql

最後會印出顧客數 2,461、觀察滿 30 天 1,458、空值 0。

步驟 3:建模型並分群

bq query --nouse_legacy_sql < segmentation/model.sql
bq query --nouse_legacy_sql < segmentation/predict.sql

建模型要一到幾分鐘,大部分時間在排隊,完成後 mart_customer_segment 會有 2,461 列。

步驟 4:看輪廓與揭曉

bq query --nouse_legacy_sql --format=pretty < segmentation/profile.sql
bq query --nouse_legacy_sql --format=pretty < segmentation/reveal.sql

先看輪廓替每一群取名字,再看揭曉表,群的編號甚至分法都可能和文章不同,對照輪廓就認得出來,揭曉表會分成觀察滿 30 天與未滿 30 天兩段,文章的對照表是前一段,3.2 的 Davies-Bouldin 比較要用 --compare 建出另外三個模型後,再執行 segmentation/evaluate.sql,5 群的揭曉表則用 segmentation/reveal_models.sql。

5.4 驗證成果

  • seg_features 2,461 列,觀察滿 30 天 1,458 人
  • 浴巾大量客集中在同一群,其他類型怎麼分每次可能不同
  • run.sh 的 8 項檢查全部通過,其中一項會確認特徵、模型與分群的 SQL 都沒有讀 martech_gt

5.5 用完後怎麼處理

bq rm -f -m martech_dw.seg_kmeans_k4
bq rm -f -m martech_dw.seg_kmeans_k3
bq rm -f -m martech_dw.seg_kmeans_k5
bq rm -f -m martech_dw.seg_kmeans_k4_all

後三行是用了 --compare 才需要,模型和表都很小,在每月 10 GiB 的免費儲存額度內,mart_customer_segment 之後的驗收會用到,建議保留,模型刪掉之後要重建才能替新顧客分群,重建一次約新台幣 0.1 元。


6. 工程實務避坑指南

  1. 沒回購的欄位不能留空:BigQuery ML 會用平均值補空值,沒回購的人會被補成平均回購間隔,看起來像會回來的人
  2. 答案不能進特徵:答案表放在另一個資料集,特徵與模型的 SQL 只讀 martech_dw,把答案當特徵分群,分數再高也沒有意義
  3. 觀察未滿 30 天的人要另外標記:剛下單的人距今天數小、回購間隔也小,會被當成常回來的人,今天兩個對照模型分別有 248 和 176 個沉睡客因此被分進回購的襪子群,這些人不能直接放進名單
  4. 群的編號和分法每次都可能不同:重建模型後群 1 可能變成群 3,同一份資料甚至會分出不同的群,今天重跑就從依品類分變成依有沒有回購分襪子客,報表和名單要靠輪廓認群,不要把編號寫死在下游
  5. 指標最好不等於最接近真實:4 群的 Davies-Bouldin 最好,但分不出沉睡客,5 群才分得出大部分,分幾群要先想清楚要拿結果做什麼,而且在看答案前決定
  6. CREATE MODEL 不在免費額度內:一定要先彙總成小表再訓練,反覆試分群數時每個模型都會計費

7. 總結與明日預告

今天把 1,458 位觀察滿 30 天的顧客整理成 10 個購買行為特徵,用 BigQuery ML 的 K-means 分成 4 群,分出組合客、洗臉巾客、浴巾客和襪子客,揭曉之後浴巾大量客和高頻買襪客各自集中在一群,新手組合客約七成三對得上,但沉睡客散在四群裡,因為他們的第一筆訂單和同品類的顧客幾乎一樣。

回到篇名,資料自己分組確實能看出顧客只有幾種人,但 4 群分出來的是「買什麼」的差別,「會不會回來」要等觀察夠久才看得出來,這也是為什麼觀察不夠久的新顧客要另外標記,不能直接放進名單。

明日預告:Day 12《哪種客人值得多投廣告?讓機器學習預測顧客的長期價值》,今天的分群要等顧客回購才分得準,明天換個角度,只用第一筆訂單就知道的資訊,讓 BigQuery ML 預測一位新顧客接下來 30 天還會帶來多少營收,再算出哪個通路帶來的客人最值得多投廣告!


上一篇
Day 10 | 同一份資料問 AI 十次,不用付十次錢的快取機制
下一篇
Day 12 | 哪種客人值得多投廣告?讓機器學習預測顧客的長期價值
系列文
AI-Driven MarTech:用 Google Cloud + Vertex AI 打造全自動廣告歸因與多模態素材分析系統 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言