Lompat ke konten
nalar

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.

Unduh lab.ipynb

Lab Minggu 5 — FP-Growth & Evaluasi Aturan Asosiasi

Tujuan lab:

  1. Membangun & mencetak FP-Tree dari contoh Han & Kamber.
  2. Membandingkan kecepatan Apriori vs. FP-Growth (mlxtend) pada dataset ritel.
  3. Membangkitkan aturan asosiasi dan memilih aturan dengan lift > 1.
  4. 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

  1. Gunakan tracemalloc untuk membandingkan puncak memori apriori vs. fpgrowth pada min_support 0.01.
  2. Saring aturan dengan conviction > 1.5. Bandingkan dengan saringan lift > 1.5.
  3. Implementasikan fpgrowth dari nol (lihat exercise.py) dan pastikan hasilnya sama dengan mlxtend.
  4. 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.