Machine Learning - Apriori

Apriori 不是一段程式,而是一套把「共現」化為「決策」的語言。是一個經典的關聯規則探勘演算法,目的為從數據中找出頻繁項集 (Frequent Itemsets) 及這些項目集之間的關聯性。

謝志謙
謝志謙
2 min read
Table of Contents

關聯規則探勘的問題,看似朴素,但實際上卻相當複雜。它不僅涉及到大量的數據處理,還需要考慮到各種不同的度量標準,以便從中提取出有價值的資訊。因為在成千上萬筆交易中,哪些項目「總是一起」出現? 真正困難在於組合爆炸,若有 10000 件商品,潛在組合多到無法枚舉。而 Apriori 的偉大之處是把「可搜尋性」建立在反單調性 (anti-monotonicity) 之上,讓我們能以數學性質剃除海量不必要的候選,保留真有機會成為規則的組合。

單調性 (monotonicity): 指的是某個屬性隨集合擴大而增加,而「反單調性」則是隨集合擴大而減少的特性。在關聯規則中,當你把項目集變大 (例如 {牛奶} → {牛奶, 麵包}),它的出現次數 (Support) 只會相同或更小,不可能變多,這個「越加項,支持度越低」的特性,就是 Support 的反單調性。

問題定義:從交易到規則

資料型態: 一組交易 $T={t_1,\dots,t_n}$,每筆交易 $t$ 是項目集合 $I={i_1,\dots,i_m}$ 的子集。

我們尋找的對象是關聯規則: $X \rightarrow Y$,其中 $X, Y \subseteq I$、$X \cap Y = \varnothing$。

基本度量:

  • Support: $\text{supp}(X) = \frac{|{t \in T: X \subseteq t}|}{|T|}$,即 $X$ 在所有交易中的出現比例。
  • Confidence: $\text{conf}(X \rightarrow Y) = \frac{\text{supp}(X \cup Y)}{\text{supp}(X)}$,觀察買了 $X$ 之後同時買 $Y$ 的機率。
  • Lift: $\text{lift}(X \rightarrow Y) = \frac{\text{supp}(X \cup Y)}{\text{supp}(X)\text{supp}(Y)}$,衡量相對於獨立假設的加成(>1 表正向關聯)。

延伸常用度量 (利於排序與風控):

  • Leverage: $\text{lev}(X \rightarrow Y) = \text{supp}(X \cup Y) - \text{supp}(X)\text{supp}(Y)$ (絕對提升量)。
  • Conviction: $\text{conv}(X \rightarrow Y)=\frac{1-\text{supp}(Y)}{1-\text{conf}(X \rightarrow Y)}$ (「若 $X$ 發生而 $Y$ 未發生」的驚訝程度)。

數學原理: 反單調性與可搜尋性

頻繁項集 (frequent itemset) 的定義: 若 $\text{supp}(X) \ge \text{min support}$,則 $X$ 為頻繁。

Apriori 的核心斷言:

Apriori Principle (反單調性): 若項集 $X$ 為頻繁,則 $X$ 的所有子集皆頻繁;反之,若 $X$ 的任一子集不頻繁,$X$ 必不頻繁。

這帶來兩個關鍵操作:

  1. 候選生成 (self-join): 由 $k$-項頻繁集生成 $(k!+!1)$-項候選。
  2. 剪枝 (prune): 若候選的任一 $k$-子集不頻繁,直接丟棄該候選。

因此,我們僅需在「有可能頻繁」的前提下計數支援度,將組合空間由天文級縮至可管理的規模,時間成本主要來自兩部分:

  1. 候選數量 (受 $\text{min support}$ 與資料稀疏度影響)
  2. 支援度計數 (I/O 密集)

空間成本則與候選表、雜湊結構、與交易壓縮格式 (如稀疏編碼) 相關。

資料準備: 從交易表到 one-hot

Apriori 假設輸入為交易 × 項目的 one-hot 矩陣。常見來源型式與轉換:

  1. 交易-項目明細表 (tid, item): 先 groupby 交易再 pivot。
  2. 品類/屬性型項: 可考慮展開為虛擬變數 (如 size_M、color_blue)。
  3. 去噪與最小出現次數: 先對低頻項做過濾,避免稀疏尾項拖慢搜尋。
  4. 稀疏化: 對超大型資料用稀疏矩陣 (scipy.sparse) 以節省記憶體。

實作流程

重點不只是「跑出規則」,而是以可解釋的步驟建構 pipeline: 資料清理 → 編碼 → 頻繁項集 → 規則 → 篩選 → 詮釋 → 驗證。

import pandas as pd
from mlxtend.frequent_patterns import apriori, association_rules

df = pd.DataFrame({
    "ID": [1, 2, 3, 4, 5, 6],
    "Onion": [1, 0, 0, 1, 1, 1],
    "Potato": [1, 1, 0, 1, 1, 1],
    "Burger": [1, 1, 0, 0, 1, 1],
    "Milk": [0, 1, 1, 1, 0, 1],
    "Beer": [0, 0, 1, 0, 1, 0]
}, dtype=bool)

frequent_itemsets = apriori(df[['Onion', 'Potato', 'Burger', 'Milk', 'Beer']],
                            min_support=0.5,
                            use_colnames=True)

rules = association_rules(frequent_itemsets,
                          metric='lift',
                          min_threshold=1)

rules = rules[rules["lift"] > 1]

print(rules)

結果觀察建議:

  • 請同時觀察 support (置信度的基礎樣本量) 與 lift (對隨機的增益),避免高 conf、低 supp 的脆弱規則誤導。
  • leverage 有助挑出「絕對增益」較大的規則;conviction 在 conf 相近時可區分非對稱性。

門檻設定與評估: 如何避免兩個極端?

  • in_support 太高: 只剩高度普遍的「必買」規則 (資訊量低)。
  • min_support 太低: 候選爆炸、效能崩潰且噪音規則充斥。

實務策略:

  1. 先以探索性分布決定區間 (觀察單品與雙品出現率的對數分布)。
  2. 逐步下修 support,同步加入 min_confidence / min_lift 作為「雙閥」過濾。
  3. 使用 holdout 期 (如以月份切分) 驗證規則是否穩定 (support 漂移不宜過大)。

排序策略 (多目標):

  • 商業動機導向 (毛利 × leverage × lift)
  • 風控導向 (conviction、向量化後的穩定性分數)
  • 行銷導向 (群體覆蓋率、與策略客群的一致性)

效能調校: 把時間花在值得的地方

  • 事前去噪: 刪除極低頻項、合併長尾同義項 (如相同 SKU 的不同拼寫)。
  • 欄位裁剪: 只保留策略相關品類,減少項目宇宙。
  • 交易壓縮: 以 set/bitset 表示交易;或使用稀疏矩陣 (scipy) 以節省 RAM。
  • 分批/增量: 以時間窗分塊計數,再合併支持度 (需小心去重)。
  • 合理平行化: 在候選計數階段做切分 (注意 I/O 瓶頸)。

常見誤區與反例思考

  1. 把關聯當因果: ${\text{lift}>1}$ 不代表 $X$ 導致 $Y$;可能是共同原因或季節性;需做時間序列對照與干擾項控制。
  2. 忽略樣本基礎: 高 confidence、低 support 的規則常不穩定 (對冷門長尾更甚)。
  3. 只看 lift: 在策略端,leverage 往往更貼近實際增益 (多賣了多少比例)。
  4. 規則冗餘: $X \cup {a}\rightarrow Y$ 的 conf 若與 $X \rightarrow Y$ 幾乎相同,應做冗餘規則剔除 (closed/maximal itemsets 的思路)。
  5. 資料漂移: 促銷、換季、上新會改變支持度分布,規則須定期重採與回測。

結語: Apriori 的真正價值

Apriori 的價值,不在「找到最多規則」,而是讓我們以可計算的方式理解「一起發生」的語法,當你能把 support 的穩健、confidence 的可用、lift 的意義、leverage 的商業價值與 conviction 的不對稱風險,編織成一套「可行的決策語言」,Apriori 才算學會,它是資料與行為之間的翻譯器——把共現變成路徑,把路徑變成行動。

What are your thoughts?

Reading List