FP-Growth & Evaluasi Aturan Asosiasi
Struktur FP-Tree, algoritma FP-Growth tanpa pembangkitan kandidat, pembentukan aturan asosiasi, serta metrik lift, leverage, dan conviction untuk menilai aturan.
Notebook lab (pratinjau)
Unduh lalu jalankan di Jupyter, VS Code, atau Google Colab.
Lab Minggu 5 — FP-Growth & Evaluasi Aturan Asosiasi
Tujuan lab:
- Membangun & mencetak FP-Tree dari contoh Han & Kamber.
- Membandingkan kecepatan Apriori vs. FP-Growth (mlxtend) pada dataset ritel.
- Membangkitkan aturan asosiasi dan memilih aturan dengan lift > 1.
- Menerjemahkan aturan menjadi strategi bisnis.
[1]
import sys
sys.path.insert(0, "..")
import time
import pandas as pd
import matplotlib.pyplot as plt
from common.datasets import transaksi_contoh, transaksi_ritel
1. FP-Tree dari nol
[2]
class Node:
def __init__(self, item, parent):
self.item, self.parent, self.count, self.children = item, parent, 0, {}
def bangun_fptree(transaksi, min_count):
cnt = {}
for t in transaksi:
for i in t:
cnt[i] = cnt.get(i, 0) + 1
flist = sorted((i for i in cnt if cnt[i] >= min_count), key=lambda i: (-cnt[i], i))
rank = {i: r for r, i in enumerate(flist)}
root, header = Node(None, None), {i: [] for i in flist}
for t in transaksi:
node = root
for i in sorted((i for i in t if i in rank), key=rank.get):
if i not in node.children:
node.children[i] = Node(i, node)
header[i].append(node.children[i])
node = node.children[i]
node.count += 1
return root, header, flist
def cetak(node, indent=""):
for anak in node.children.values():
print(f"{indent}└── {anak.item}:{anak.count}")
cetak(anak, indent + " ")
root, header, flist = bangun_fptree(transaksi_contoh(), 2)
print("F-list:", flist)
print("null")
cetak(root)
Conditional pattern base
[3]
def cpb(header, item):
hasil = []
for node in header[item]:
path, p = [], node.parent
while p.item is not None:
path.append(p.item)
p = p.parent
if path:
hasil.append((path[::-1], node.count))
return hasil
for item in reversed(flist):
print(f"{item}: {cpb(header, item)}")
2. Apriori vs. FP-Growth (mlxtend)
[4]
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori, fpgrowth, association_rules
ritel = transaksi_ritel(5000, seed=2)
te = TransactionEncoder()
onehot = pd.DataFrame(te.fit(ritel).transform(ritel), columns=te.columns_)
print(onehot.shape)
[5]
baris = []
for ms in [0.1, 0.05, 0.03, 0.02, 0.01]:
for nama, fn in [("apriori", apriori), ("fpgrowth", fpgrowth)]:
t0 = time.perf_counter()
hasil = fn(onehot, min_support=ms, use_colnames=True)
baris.append({"algoritma": nama, "min_support": ms,
"waktu_ms": (time.perf_counter() - t0) * 1000, "itemset": len(hasil)})
banding = pd.DataFrame(baris)
banding.pivot(index="min_support", columns="algoritma", values=["waktu_ms", "itemset"]).round(1)
[6]
banding.pivot(index="min_support", columns="algoritma", values="waktu_ms").plot(
marker="o", title="Waktu komputasi (ms)")
plt.gca().invert_xaxis()
plt.show()
Jumlah itemset identik — kedua algoritma menemukan pola yang sama, hanya caranya berbeda. Mengukur memori bisa dicoba dengan
tracemalloc(lihat Coba sendiri).
3. Membangkitkan aturan & metrik
[7]
fi = fpgrowth(onehot, min_support=0.03, use_colnames=True)
rules = association_rules(fi, metric="confidence", min_threshold=0.3)
rules = rules[["antecedents", "consequents", "support", "confidence", "lift", "leverage", "conviction"]]
rules.sort_values("lift", ascending=False).head(10).round(3)
Verifikasi manual satu aturan:
[8]
r = rules.sort_values("lift", ascending=False).iloc[0]
A, B = set(r.antecedents), set(r.consequents)
sA = onehot[list(A)].all(axis=1).mean()
sB = onehot[list(B)].all(axis=1).mean()
sAB = onehot[list(A | B)].all(axis=1).mean()
print(f"{A} => {B}")
print(f"confidence = {sAB / sA:.3f} lift = {sAB / (sA * sB):.3f} "
f"leverage = {sAB - sA * sB:.3f} conviction = {(1 - sB) / (1 - sAB / sA):.3f}")
4. Confidence vs. lift
[9]
plt.scatter(rules["support"], rules["confidence"], c=rules["lift"], cmap="coolwarm", s=25)
plt.colorbar(label="lift")
plt.xlabel("support"); plt.ylabel("confidence")
plt.title("Aturan asosiasi (warna = lift)")
plt.show()
[10]
print("Aturan confidence ≥ 0.3 tetapi lift < 1 (korelasi negatif/menyesatkan):")
rules[rules["lift"] < 1].sort_values("confidence", ascending=False).head().round(3)
5. Aturan teratas untuk bisnis (lift > 1)
[11]
top = rules[(rules["lift"] > 1.2)].sort_values(["lift", "support"], ascending=False).head(8).copy()
top["aturan"] = top.apply(lambda r: f"{set(r.antecedents)} => {set(r.consequents)}", axis=1)
top[["aturan", "support", "confidence", "lift"]].round(3)
Contoh interpretasi:
{mentega} => {roti}: lift tinggi & support tinggi → letakkan berdekatan, promo bundling.{gula} => {kopi}: pembeli gula cenderung membeli kopi → rekomendasi "sering dibeli bersama".
✍️ Coba sendiri
- Gunakan
tracemallocuntuk membandingkan puncak memori apriori vs. fpgrowth pada min_support 0.01. - Saring aturan dengan
conviction > 1.5. Bandingkan dengan saringanlift > 1.5. - Implementasikan
fpgrowthdari nol (lihatexercise.py) dan pastikan hasilnya sama dengan mlxtend. - Tulis 3 aturan teratas beserta strategi bisnisnya (penempatan, bundling, rekomendasi).
[12]
# 1.
import tracemalloc
[13]
# 2.
Strategi no. 4:
- ...
Selanjutnya
Kerjakan kuis dan exercise.py, lalu jalankan python check.py 5 dari folder utama.