Lompat ke konten
nalar

Algoritma Apriori & Frequent Itemsets

Market basket analysis, itemset, support, confidence, prinsip Apriori (anti-monoton), pembentukan kandidat join & prune, serta closed dan maximal itemset.

Notebook lab (pratinjau)

Unduh lalu jalankan di Jupyter, VS Code, atau Google Colab.

Unduh lab.ipynb

Lab Minggu 4 — Apriori & Frequent Itemsets

Tujuan lab:

  1. Menghitung support & confidence secara manual dengan Python.
  2. Menelusuri algoritma Apriori langkah demi langkah pada contoh Han & Kamber.
  3. Menjalankan Apriori dengan mlxtend pada data transaksi ritel.
  4. Melihat efek nilai min_support terhadap jumlah itemset dan waktu komputasi.
[1]
import sys
sys.path.insert(0, "..")

from itertools import combinations
import time

import pandas as pd
import matplotlib.pyplot as plt

from common.datasets import transaksi_contoh, transaksi_ritel

1. Support & confidence manual

[2]
trx = [["roti", "susu"], ["roti", "mentega", "telur"], ["susu", "mentega", "kopi"],
       ["roti", "susu", "mentega"], ["roti", "susu", "kopi"]]

def support(transaksi, itemset):
    s = set(itemset)
    return sum(s <= set(t) for t in transaksi) / len(transaksi)

print("s(roti)        =", support(trx, {"roti"}))
print("s(roti, susu)  =", support(trx, {"roti", "susu"}))
print("conf(roti=>susu) =", support(trx, {"roti", "susu"}) / support(trx, {"roti"}))

2. Apriori langkah demi langkah (Han & Kamber, min_sup count = 2)

[3]
T = [set(t) for t in transaksi_contoh()]
for i, t in enumerate(T, 1):
    print(f"T{i}00: {sorted(t)}")
MIN = 2

def hitung(kandidat):
    return {c: sum(c <= t for t in T) for c in kandidat}
[4]
# Iterasi 1
C1 = {frozenset([i]) for t in T for i in t}
cnt = hitung(C1)
L1 = {c for c, v in cnt.items() if v >= MIN}
pd.Series({",".join(sorted(c)): v for c, v in cnt.items()}).sort_index()
[5]
# Iterasi 2: semua pasangan dari L1
items = sorted(i for c in L1 for i in c)
C2 = {frozenset(p) for p in combinations(items, 2)}
cnt = hitung(C2)
L2 = {c for c, v in cnt.items() if v >= MIN}
tabel = pd.DataFrame([(",".join(sorted(c)), v, v >= MIN) for c, v in cnt.items()],
                     columns=["itemset", "count", "frequent"]).sort_values("itemset")
tabel
[6]
# Iterasi 3: JOIN lalu PRUNE
def join(L_prev, k):
    srt = sorted(sorted(x) for x in L_prev)
    hasil = set()
    for i in range(len(srt)):
        for j in range(i + 1, len(srt)):
            if srt[i][:k - 2] == srt[j][:k - 2]:
                hasil.add(frozenset(srt[i]) | frozenset(srt[j]))
    return hasil

C3_join = join(L2, 3)
print("Hasil JOIN :", [sorted(c) for c in C3_join])
C3 = {c for c in C3_join if all(frozenset(s) in L2 for s in combinations(c, 2))}
print("Hasil PRUNE:", [sorted(c) for c in C3])
cnt = hitung(C3)
L3 = {c for c, v in cnt.items() if v >= MIN}
print("L3:", {",".join(sorted(c)): v for c, v in cnt.items() if v >= MIN})
[7]
# Iterasi 4
C4 = {c for c in join(L3, 4) if all(frozenset(s) in L3 for s in combinations(c, 3))}
print("C4:", C4, "-> kosong, algoritma berhenti")
print("Total frequent itemset:", len(L1) + len(L2) + len(L3))

3. Data ritel dengan mlxtend

[8]
from mlxtend.preprocessing import TransactionEncoder
from mlxtend.frequent_patterns import apriori

ritel = transaksi_ritel()
print(len(ritel), "transaksi; contoh:", ritel[:3])

te = TransactionEncoder()
onehot = pd.DataFrame(te.fit(ritel).transform(ritel), columns=te.columns_)
onehot.head()
[9]
onehot.mean().sort_values(ascending=False).plot(kind="bar", figsize=(10, 3), title="Support 1-itemset")
plt.show()
[10]
fi = apriori(onehot, min_support=0.05, use_colnames=True)
fi["panjang"] = fi["itemsets"].apply(len)
fi.sort_values("support", ascending=False).query("panjang >= 2").head(15)

Pola yang "ditanam" di generator data (roti–mentega, kopi–gula, sereal–susu, mie_instan–telur) muncul di atas.

4. Efek min_support

[11]
hasil = []
for ms in [0.2, 0.15, 0.1, 0.07, 0.05, 0.03, 0.02, 0.01]:
    t0 = time.perf_counter()
    f = apriori(onehot, min_support=ms, use_colnames=True)
    hasil.append({"min_support": ms, "jumlah_itemset": len(f),
                  "waktu_ms": (time.perf_counter() - t0) * 1000})
efek = pd.DataFrame(hasil)
efek
[12]
efek.plot(x="min_support", y="jumlah_itemset", marker="o", logy=True,
          title="Semakin kecil min_support, itemset meledak")
plt.gca().invert_xaxis()
plt.show()

5. Maximal itemsets

[13]
fs = set(apriori(onehot, min_support=0.05, use_colnames=True)["itemsets"])
maximal = [x for x in fs if not any(x < y for y in fs)]
print(len(fs), "frequent ->", len(maximal), "maximal")
sorted(sorted(x) for x in maximal if len(x) > 1)

✍️ Coba sendiri

  1. Hitung confidence {sereal} => {susu} dan {susu} => {sereal} pada data ritel. Mengapa berbeda?
  2. Tampilkan semua 3-itemset dengan min_support 0.02. Adakah pola {roti, susu, telur}?
  3. Implementasikan fungsi apriori_saya(transaksi, min_support) sendiri (lihat exercise.py) lalu bandingkan hasilnya dengan mlxtend.
  4. Rekomendasi bisnis: berdasarkan pasangan produk teratas, usulkan 2 strategi penempatan/promo.
[14]
# 1.
[15]
# 2.
[16]
# 3.

Rekomendasi no. 4:

  • ...

Selanjutnya

Kerjakan kuis dan exercise.py, lalu jalankan python check.py 4 dari folder utama.