Latent Dirichlet allocation (LDA) adalah metode pemodelan topik yang membaca hitungan kata tanpa label dan menghasilkan dua jenis distribusi sekaligus, yaitu distribusi kata untuk setiap topik dan distribusi topik untuk setiap dokumen. Topik ini membahas LDA pada tingkat pengenalan, kemudian melatih model LDA pertama dengan Gensim pada dua puluh empat dokumen sintetis dari tiga tema. Setelah topik ini dibaca, daftar kata tiap topik dan campuran topik satu dokumen dapat dibaca langsung dari keluaran Gensim.
Topik sebagai distribusi kata#
Pada LDA, satu topik bukan wadah kata yang bersifat ya atau tidak, melainkan distribusi probabilitas atas seluruh kosakata. Distribusi tersebut memberi bobot probabilitas pada setiap kata dan jumlah seluruh bobotnya sama dengan satu. Topik yang mewakili tema pasar memberi probabilitas tinggi pada kata seperti sayur dan pasar, probabilitas menengah pada kata seperti kangkung, dan probabilitas hampir nol pada kata seperti sensor. Angka probabilitas inilah yang membuat topik dapat dibaca dan dibandingkan secara terukur.
Dokumen kemudian dipandang sebagai campuran dari K topik. Campuran itu menghasilkan distribusi kata untuk dokumen melalui penjumlahan berbobot berikut.
Simbol adalah distribusi kata pada topik , sedangkan adalah bagian topik dalam dokumen , dan jumlah untuk seluruh topik sama dengan satu. LDA mempelajari kedua jenis distribusi itu hanya dari hitungan kata, tanpa label apa pun. Nama Dirichlet menunjuk distribusi prior yang menjadi bagian formulasi model, dan rincian estimasinya berada di luar lingkup pengenalan ini.
Dokumen sebagai campuran topik#
Satu dokumen dapat berbicara pada beberapa tema sekaligus, misalnya catatan yang sebagian besar membahas belanja sayur dan sedikit membahas perbaikan peralatan. LDA menyatakan hal itu lewat bagian keanggotaan, yaitu nilai untuk setiap topik. Diagram berikut menggambarkan satu dokumen yang campuran topiknya didominasi satu tema.
Diagram tersebut menunjukkan dua hal yang perlu dipegang. Nilai bagian terbesar menunjukkan tema utama dokumen, sedangkan nilai kecil yang tersisa tetap wajar karena dokumen memang boleh menyentuh lebih dari satu tema. Nomor topik seperti topik 0 atau topik 2 hanyalah penomoran mesin, sehingga tema yang sesungguhnya selalu dibaca dari daftar katanya, bukan dari nomornya.
Dokumen yang benar-benar membahas dua tema akan menempati nilai bagian yang berdekatan pada dua topik sekaligus. Bagian kecil yang tersebar di semua topik biasanya lahir dari kata-kata umum seperti kata sambung, dan bagian itu tidak perlu dibaca sebagai tema. Pembacaan campuran karenanya selalu dicocokkan dengan isi dokumen, bukan ditebak dari angkanya saja.
Melatih LDA pertama dengan Gensim#
Gensim menyediakan alur pelatihan LDA dalam tiga langkah. Pertama, teks ditokenisasi menjadi daftar kata. Kedua, Dictionary memetakan setiap kata unik ke nomor kosakata, lalu doc2bow mengubah setiap dokumen menjadi daftar pasangan nomor kata dan hitungannya. Ketiga, LdaModel dilatih pada hasil tersebut. Parameter yang disetel adalah num_topics untuk jumlah topik, random_state=42 agar hasil dapat diulang, passes=15 untuk jumlah lintasan penuh atas korpus, iterations=200 untuk batas iterasi internal, alpha="symmetric" sebagai prior campuran topik dokumen, serta eta=0.01 yang membuat distribusi kata tiap topik lebih tajam pada korpus kecil.
import warnings
warnings.filterwarnings("ignore")
import logging
logging.getLogger("gensim").setLevel(logging.ERROR)
import re
from gensim.corpora import Dictionary
from gensim.models import LdaModel
# Dua puluh empat dokumen sintetis dari tiga tema yang jelas.
dokumen = [
"harga sayur di pasar pagi menjadi lebih mahal karena panen sayur terlambat",
"belanja sayur mingguan mencatat bayam wortel dan kangkung dari pasar",
"petani sayur membawa hasil panen ke kios pasar setiap pagi",
"pedagang pasar menaikkan harga bayam dan wortel saat panen berkurang",
"keranjang belanja berisi sayur segar kangkung dan bayam dari kios pasar",
"dagang sayur di pasar menghitung harga hasil panen setiap hari",
"belanja sayur untuk dapur mencatat harga wortel dan kangkung",
"harga sayur turun ketika petani panen melimpah di pasar",
"peminjaman buku di perpustakaan dicatat petugas pada kartu anggota",
"anggota perpustakaan mengembalikan buku pinjaman pada rak katalog",
"katalog koleksi perpustakaan memuat judul dan penulis setiap buku",
"rak buku bacaan anak ditata ulang oleh petugas perpustakaan",
"pengembalian buku terlambat dikenakan denda pada peminjaman berikutnya",
"koleksi buku referensi di perpustakaan hanya dibaca di tempat",
"pengadaan buku baru menambah koleksi rak perpustakaan sekolah",
"petugas perpustakaan memperbarui katalog peminjaman dan pengembalian buku",
"sensor suhu gudang merekam bacaan pada log pemantauan",
"bacaan sensor suhu naik ketika pintu gudang terbuka",
"teknisi mengkalibrasi sensor suhu dan peralatan pendukungnya",
"log suhu gudang disimpan pada komputer pemantauan peralatan",
"alarm suhu berbunyi ketika bacaan gudang melewati batas",
"teknisi memeriksa peralatan sensor yang bacaannya tidak stabil",
"panel indikator menampilkan bacaan suhu mesin pengering",
"pemeliharaan peralatan gudang dijadwalkan setelah kalibrasi sensor",
]
# Tokenisasi sederhana: huruf kecil dan rangkaian alfabet.
teks_token = [re.findall(r"[a-z]+", d.lower()) for d in dokumen]
# Dictionary memetakan setiap kata unik ke nomor kosakata.
dictionary = Dictionary(teks_token)
print("Jumlah kata unik pada kosakata:", len(dictionary))
# doc2bow mengubah setiap dokumen menjadi daftar pasangan (nomor kata, hitungan).
corpus = [dictionary.doc2bow(t) for t in teks_token]
print("Bentuk bow dokumen pertama:", [(dictionary[i], n) for i, n in corpus[0]])
# LDA mempelajari tiga topik dari hitungan kata saja.
# eta diperkecil agar distribusi kata pada topik lebih tajam di korpus kecil.
lda = LdaModel(
corpus=corpus,
id2word=dictionary,
num_topics=3,
random_state=42,
passes=15,
iterations=200,
alpha="symmetric",
eta=0.01,
)
# Setiap topik ditampilkan sebagai distribusi kata teratasnya.
for t in lda.print_topics(num_words=6):
print(t)
# Distribusi topik untuk satu dokumen.
print("Dokumen:", dokumen[0])
print("Campuran topik:", [(k, round(float(p), 4))
for k, p in lda.get_document_topics(corpus[0], minimum_probability=0.0)])Jumlah kata unik pada kosakata: 107
Bentuk bow dokumen pertama: [('di', 1), ('harga', 1), ('karena', 1), ('lebih', 1), ('mahal', 1), ('menjadi', 1), ('pagi', 1), ('panen', 1), ('pasar', 1), ('sayur', 2), ('terlambat', 1)]
(0, '0.130*"buku" + 0.113*"perpustakaan" + 0.049*"katalog" + 0.049*"rak" + 0.049*"peminjaman" + 0.049*"petugas"')
(1, '0.097*"sensor" + 0.094*"suhu" + 0.079*"peralatan" + 0.076*"gudang" + 0.060*"di" + 0.048*"pada"')
(2, '0.079*"sayur" + 0.069*"pasar" + 0.050*"harga" + 0.050*"panen" + 0.040*"dan" + 0.030*"kangkung"')
Dokumen: harga sayur di pasar pagi menjadi lebih mahal karena panen sayur terlambat
Campuran topik: [(0, 0.0261), (1, 0.0263), (2, 0.9476)]Keluaran itu menunjukkan ketiga topik terbentuk dengan tema yang jelas. Topik 0 mengelompokkan kosakata perpustakaan dengan buku sebagai kata teratasnya, topik 1 mengelompokkan kosakata sensor dan suhu, sedangkan topik 2 mengelompokkan kosakata pasar. Kata sambung umum seperti di dan pada ikut muncul di antara kata teratas topik 1, dan perilaku semacam itu menjadi contoh saat penafsiran model dibahas. Campuran topik dokumen pertama menempatkan 0.9476 bagian pada topik 2, sesuai dengan isinya yang membahas harga sayur, dengan sisa kecil pada dua topik lainnya. Perintah berikut mengulangi pelatihan yang sama dari terminal.
# jalankan pelatihan LDA dari folder tempat berkas disimpan
python3 latih-lda.pyJumlah kata unik pada kosakata: 107
Bentuk bow dokumen pertama: [('di', 1), ('harga', 1), ('karena', 1), ('lebih', 1), ('mahal', 1), ('menjadi', 1), ('pagi', 1), ('panen', 1), ('pasar', 1), ('sayur', 2), ('terlambat', 1)]
(0, '0.130*"buku" + 0.113*"perpustakaan" + 0.049*"katalog" + 0.049*"rak" + 0.049*"peminjaman" + 0.049*"petugas"')
(1, '0.097*"sensor" + 0.094*"suhu" + 0.079*"peralatan" + 0.076*"gudang" + 0.060*"di" + 0.048*"pada"')
(2, '0.079*"sayur" + 0.069*"pasar" + 0.050*"harga" + 0.050*"panen" + 0.040*"dan" + 0.030*"kangkung"')
Dokumen: harga sayur di pasar pagi menjadi lebih mahal karena panen sayur terlambat
Campuran topik: [(0, 0.0261), (1, 0.0263), (2, 0.9476)]Kesalahan umum#
Menganggap nomor topik sebagai label tetap. Topik 0 pada satu pelatihan tidak menjamin menjadi topik 0 dengan tema yang sama pada pelatihan berikutnya, karena penomorannya bergantung pada inisialisasi acak. Dua pelatihan dengan random_state berbeda pada korpus yang sama dapat saling menukar urutan topiknya. Baca selalu daftar kata topik untuk mengetahui temanya sebelum memakai nomornya.
Mengira LDA membaca urutan kata. Masukan LDA adalah bag of words berupa hitungan, sehingga urutan kata hilang sejak doc2bow. Ungkapan seperti kartu anggota diperlakukan sebagai dua kata terpisah, dan model tidak mengetahui bahwa keduanya satu frasa. Daftar kata topik pun berupa kosakata lepas, bukan frasa utuh.
Menetapkan num_topics lebih banyak dari yang korpus dukung. Korpus kecil dengan terlalu banyak topik memecah tema menjadi potongan yang sulit dibaca. Tema pasar pada demo ini, misalnya, terpecah dua ketika jumlah topik dinaikkan menjadi empat. Jumlah topik dipilih sesuai perkiraan tema dan diuji dengan skor koherensi pada pembahasan membaca model topik.
Melatih tanpa random_state. Inisialisasi LDA bersifat acak, sehingga pelatihan tanpa random_state menghasilkan penomoran dan kadang tema yang berbeda pada setiap eksekusi. Perbedaan antareksekusi semacam itu menyulitkan pembacaan yang membandingkan dua model. Penyetelan seperti random_state=42 membuat eksperimen dapat diulang dan dibandingkan.
Ringkasan#
- Topik pada LDA adalah distribusi probabilitas atas kosakata, sedangkan dokumen adalah campuran topik yang bagian tiap topiknya berjumlah satu.
- Rumus menghubungkan distribusi kata per topik dengan campuran topik per dokumen.
- Pelatihan dengan Gensim berjalan melalui tokenisasi,
Dictionary,doc2bow, danLdaModel, denganrandom_stateserta jumlah topik sebagai penyetelan utama. - Daftar kata topik menunjukkan temanya, dan campuran topik pada
get_document_topicsmenunjukkan bagian setiap topik dalam satu dokumen.
Referensi#
- Topic modeling dengan Gensim LDA — dokumentasi Gensim — Panduan resmi pelatihan LDA pada Gensim beserta penyetelan parameternya.
- Gensim Documentation — RaRe Technologies
— Referensi resmi
Dictionary,doc2bow, danLdaModelyang dipakai pada topik ini. - Speech and Language Processing, draf edisi ke-3 — Jurafsky & Martin, Stanford — Bab pemodelan topik menjelaskan topik sebagai distribusi kata dan dokumen sebagai campuran topik.