Files
tugas-josjis/lab3_hit_at_k.py
T
2026-11-02 11:24:52 +07:00

109 lines
4.3 KiB
Python

from pathlib import Path
from pypdf import PdfReader
import chromadb
from chromadb.utils import embedding_functions
# ==========================================
# FUNGSI BANTU
# ==========================================
def baca_pdf(path):
reader = PdfReader(path)
return "\n".join((p.extract_text() or "") for p in reader.pages)
def potong(teks, ukuran=800, tumpang=100):
hasil, mulai = [], 0
while mulai < len(teks):
hasil.append(teks[mulai:mulai + ukuran])
mulai += ukuran - tumpang
return [h for h in hasil if h.strip()]
# ==========================================
# SETUP EMBEDDING & CLIENT
# ==========================================
emb = embedding_functions.SentenceTransformerEmbeddingFunction(
model_name="paraphrase-multilingual-MiniLM-L12-v2")
client = chromadb.PersistentClient(path="./chroma_db")
def buat_koleksi(nama, ukuran, tumpang):
try:
client.delete_collection(nama)
except Exception:
pass
kol = client.get_or_create_collection(
name=nama, embedding_function=emb,
metadata={"hnsw:space": "cosine"})
for pdf in Path("dokumen").glob("*.pdf"):
chunks = potong(baca_pdf(pdf), ukuran, tumpang)
kol.upsert(
ids=[f"{nama}-{pdf.stem}-{i}" for i in range(len(chunks))],
documents=chunks,
metadatas=[{"sumber": pdf.name, "chunk": i} for i in range(len(chunks))],
)
print(f" {nama}: {pdf.name} -> {len(chunks)} chunk")
return kol
# ==========================================
# 15 PERTANYAAN + KATA KUNCI
# (disesuaikan dengan isi PDF probabilitas)
# ==========================================
UJI = [
("What is a sample space?", "sample space"),
("What is classical probability?", "classical probability"),
("What is empirical probability?", "empirical probability"),
("What is subjective probability?", "subjective probability"),
("What is a simple event?", "simple event"),
("What is the multiplication rule?", "multiplication rule"),
("What is the addition rule?", "addition rule"),
("What are mutually exclusive events?", "mutually exclusive"),
("What is conditional probability?", "conditional probability"),
("What is the law of large numbers?", "law of large numbers"),
("What is a discrete probability distribution?", "discrete probability distribution"),
("What is a binomial experiment?", "binomial experiment"),
("What is the fundamental counting principle?", "fundamental counting principle"),
("What is the difference between permutations and combinations?", "permutation"),
("What is a random variable?", "random variable"),
]
def hit_at_k(koleksi, uji, k):
benar = 0
for pertanyaan, kunci in uji:
docs = koleksi.query(query_texts=[pertanyaan], n_results=k)["documents"][0]
if any(kunci.lower() in d.lower() for d in docs):
benar += 1
return benar / len(uji)
# ==========================================
# JALANKAN: BUAT 2 KOLEKSI
# ==========================================
print("=== MEMBUAT KOLEKSI ===")
kol_500 = buat_koleksi("chunk_500", 500, 75)
kol_1500 = buat_koleksi("chunk_1500", 1500, 225)
print("\n=== CEK ISI KOLEKSI ===")
print(f" chunk_500 : {kol_500.count()} dokumen")
print(f" chunk_1500 : {kol_1500.count()} dokumen")
# ==========================================
# HITUNG HIT@K
# ==========================================
print("\n=== TABEL HIT@K ===")
print(f"{'k':<4}{'Chunk 500':<14}{'Chunk 1500':<14}")
for k in (1, 3, 5):
print(f"{k:<4}{hit_at_k(kol_500, UJI, k):<14.2f}{hit_at_k(kol_1500, UJI, k):<14.2f}")
print("\n=== PERTANYAAN GAGAL di k=3 ===")
for pertanyaan, kunci in UJI:
ok_500 = any(kunci.lower() in d.lower()
for d in kol_500.query(query_texts=[pertanyaan], n_results=3)["documents"][0])
ok_1500 = any(kunci.lower() in d.lower()
for d in kol_1500.query(query_texts=[pertanyaan], n_results=3)["documents"][0])
if not ok_500 and not ok_1500:
print(f"X {pertanyaan} (kunci: '{kunci}')")
print("\n=== SELESAI ===")