diff --git a/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/data_level0.bin b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/data_level0.bin new file mode 100644 index 0000000..a97db4b Binary files /dev/null and b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/data_level0.bin differ diff --git a/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/header.bin b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/header.bin new file mode 100644 index 0000000..bb54792 Binary files /dev/null and b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/header.bin differ diff --git a/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/length.bin b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/length.bin new file mode 100644 index 0000000..95b1fe5 Binary files /dev/null and b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/length.bin differ diff --git a/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/link_lists.bin b/chroma_db/1a321173-a5c4-47dd-9d4b-53c387b4f017/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/data_level0.bin b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/data_level0.bin new file mode 100644 index 0000000..b008bad Binary files /dev/null and b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/data_level0.bin differ diff --git a/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/header.bin b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/header.bin new file mode 100644 index 0000000..bb54792 Binary files /dev/null and b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/header.bin differ diff --git a/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/length.bin b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/length.bin new file mode 100644 index 0000000..65afdb4 Binary files /dev/null and b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/length.bin differ diff --git a/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/link_lists.bin b/chroma_db/8b8bd10d-9131-442f-8679-ac8fb80b8be6/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/data_level0.bin b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/data_level0.bin new file mode 100644 index 0000000..eadfd73 Binary files /dev/null and b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/data_level0.bin differ diff --git a/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/header.bin b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/header.bin new file mode 100644 index 0000000..bb54792 Binary files /dev/null and b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/header.bin differ diff --git a/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/length.bin b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/length.bin new file mode 100644 index 0000000..337aa85 Binary files /dev/null and b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/length.bin differ diff --git a/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/link_lists.bin b/chroma_db/8ee3dbbb-97fc-41fc-b82d-1a898db46391/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/data_level0.bin b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/data_level0.bin new file mode 100644 index 0000000..2d6d523 Binary files /dev/null and b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/data_level0.bin differ diff --git a/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/header.bin b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/header.bin new file mode 100644 index 0000000..bb54792 Binary files /dev/null and b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/header.bin differ diff --git a/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/length.bin b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/length.bin new file mode 100644 index 0000000..cd088e3 --- /dev/null +++ b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/length.bin @@ -0,0 +1 @@ +invalid type: string "vention\n \nis\n \nnot\n \nused\n \nin\n \nevery\n \ncase\n \nbecause\n \nsometimes\n \nthe\n \nargument\n \nname\n \nand\n \nthe\n \nvariable\n \nname\n \nare\n \ndifferent.\n \nFor\n \nexample:\n \ntext\n \ncontext:\n \nshortUrlBase\n \nHere,\n \n`context`\n \nis\n \nthe\n \nargument\n \nname\n \nand\n \n`shortUrlBase`\n \nis\n \nthe\n \nvariable\n \nbeing\n \npassed\n \nto \ No newline at end of file diff --git a/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/link_lists.bin b/chroma_db/9ad1879a-6f5a-4003-a25f-df9f5ed8a1e8/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/data_level0.bin b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/data_level0.bin new file mode 100644 index 0000000..375fbb2 Binary files /dev/null and b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/data_level0.bin differ diff --git a/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/header.bin b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/header.bin new file mode 100644 index 0000000..bb54792 Binary files /dev/null and b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/header.bin differ diff --git a/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/length.bin b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/length.bin new file mode 100644 index 0000000..0009b1d Binary files /dev/null and b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/length.bin differ diff --git a/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/link_lists.bin b/chroma_db/a880ae3c-a666-416d-bd83-aeb89a723819/link_lists.bin new file mode 100644 index 0000000..e69de29 diff --git a/chroma_db/chroma.sqlite3 b/chroma_db/chroma.sqlite3 index 0d75bc1..5874374 100644 Binary files a/chroma_db/chroma.sqlite3 and b/chroma_db/chroma.sqlite3 differ diff --git a/dokumen/Problem Set 2_ Composing Concepts.pdf b/dokumen/Problem Set 2_ Composing Concepts.pdf new file mode 100644 index 0000000..b920364 Binary files /dev/null and b/dokumen/Problem Set 2_ Composing Concepts.pdf differ diff --git a/lab3_hit_at_k.py b/lab3_hit_at_k.py index 941ba1a..d523cc7 100644 --- a/lab3_hit_at_k.py +++ b/lab3_hit_at_k.py @@ -1,224 +1,109 @@ - from pathlib import Path from pypdf import PdfReader import chromadb from chromadb.utils import embedding_functions # ========================================== -# 1. MEMBACA DOKUMEN PDF +# FUNGSI BANTU # ========================================== def baca_pdf(path): reader = PdfReader(path) return "\n".join((p.extract_text() or "") for p in reader.pages) - -# ========================================== -# 2. MEMBAGI DOKUMEN MENJADI CHUNK -# ========================================== - def potong(teks, ukuran=800, tumpang=100): - hasil = [] - mulai = 0 - + 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()] - # ========================================== -# 3. PENGATURAN EMBEDDING DAN DATABASE +# SETUP EMBEDDING & CLIENT # ========================================== emb = embedding_functions.SentenceTransformerEmbeddingFunction( - model_name="paraphrase-multilingual-MiniLM-L12-v2" -) + model_name="paraphrase-multilingual-MiniLM-L12-v2") client = chromadb.PersistentClient(path="./chroma_db") - -# ========================================== -# 4. MEMBUAT KOLEKSI -# ========================================== - 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"} - ) - + name=nama, embedding_function=emb, + metadata={"hnsw:space": "cosine"}) for pdf in Path("dokumen").glob("*.pdf"): - - teks = baca_pdf(pdf) - chunks = potong(teks, ukuran, tumpang) - - if not chunks: - continue - + chunks = potong(baca_pdf(pdf), ukuran, tumpang) kol.upsert( - ids=[ - f"{nama}-{pdf.stem}-{i}" - for i in range(len(chunks)) - ], + 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)) - ] + metadatas=[{"sumber": pdf.name, "chunk": i} for i in range(len(chunks))], ) - + print(f" {nama}: {pdf.name} -> {len(chunks)} chunk") return kol - # ========================================== -# 5. 15 PERTANYAAN DAN KATA KUNCI +# 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 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"), + ("What is a random variable?", "random variable"), ] - -# ========================================== -# 6. FUNGSI HIT@K -# ========================================== - def hit_at_k(koleksi, uji, k): - benar = 0 - jumlah = min(k, koleksi.count()) - - if jumlah == 0: - return 0 - for pertanyaan, kunci in uji: - - docs = koleksi.query( - query_texts=[pertanyaan], - n_results=jumlah - )["documents"][0] - + 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) - # ========================================== -# 7. MEMBUAT DUA KOLEKSI BERBEDA +# JALANKAN: BUAT 2 KOLEKSI # ========================================== -kol_500 = buat_koleksi("chunk_500", 500, 75) +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") # ========================================== -# 8. MENAMPILKAN TABEL HASIL HIT@K +# HITUNG HIT@K # ========================================== -print("\n========== TABEL HIT@K ==========") - -print(f"{'k':<5}{'Chunk 500':<15}{'Chunk 1500':<15}") - -hasil = {} - +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}") - h500 = hit_at_k(kol_500, UJI, k) - h1500 = hit_at_k(kol_1500, UJI, k) - - hasil[k] = (h500, h1500) - - print(f"{k:<5}{h500:<15.2f}{h1500:<15.2f}") - - -# ========================================== -# 9. MENAMPILKAN PERTANYAAN YANG GAGAL -# ========================================== - -print("\n========== PERTANYAAN GAGAL DI k=3 ==========") - -gagal = [] - +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}')") - docs_500 = kol_500.query( - query_texts=[pertanyaan], - n_results=min(3, kol_500.count()) - )["documents"][0] - - docs_1500 = kol_1500.query( - query_texts=[pertanyaan], - n_results=min(3, kol_1500.count()) - )["documents"][0] - - ok_500 = any(kunci.lower() in d.lower() for d in docs_500) - ok_1500 = any(kunci.lower() in d.lower() for d in docs_1500) - - if not ok_500 or not ok_1500: - - gagal.append(pertanyaan) - - print(f"\nPertanyaan: {pertanyaan}") - print(f"Kata kunci: {kunci}") - print(f"Chunk 500 : {'Berhasil' if ok_500 else 'Gagal'}") - print(f"Chunk 1500: {'Berhasil' if ok_1500 else 'Gagal'}") - -if not gagal: - print("Semua pertanyaan berhasil ditemukan pada kedua koleksi.") - - -# ========================================== -# 10. KESIMPULAN OTOMATIS -# ========================================== - -print("\n========== KESIMPULAN ==========") - -rata_500 = sum(v[0] for v in hasil.values()) / len(hasil) -rata_1500 = sum(v[1] for v in hasil.values()) / len(hasil) - -print(f"Rata-rata Hit@K Chunk 500 : {rata_500:.2f}") -print(f"Rata-rata Hit@K Chunk 1500 : {rata_1500:.2f}") - -if rata_500 > rata_1500: - print("Chunk 500 memiliki hasil pencarian lebih baik.") -elif rata_1500 > rata_500: - print("Chunk 1500 memiliki hasil pencarian lebih baik.") -else: - print("Kedua ukuran chunk memiliki hasil rata-rata yang sama.") - -print( - f"Jumlah pertanyaan yang gagal pada minimal satu koleksi " - f"di k=3: {len(gagal)} dari {len(UJI)}." -) - -print( - "Kegagalan pencarian dapat disebabkan oleh perbedaan istilah, " - "informasi yang tersebar di beberapa chunk, atau hasil embedding " - "yang kurang relevan." -) - -print("\n========== PENGUJIAN SELESAI ==========") +print("\n=== SELESAI ===") \ No newline at end of file