Pembuka¶
Pada blog ini, saya akan membahas implementasi sederhana untuk keyword extraction atau ekstraksi kata kunci dari dokumen teks. Mungkin anda pernah menjumpai beberapa aplikasi dari keyword extraction ini, salah satunya bisa anda lihat di bagian bawah dari setiap berita yang dipublikasikan oleh detik.com. Di setiap artikel dari detik.com tertulis keyword-keyword yang diambil dari teks berita. Gambar dibawah merupakan contoh yang diambil dari artikel ini.
Dari contoh diatas bisa kita lihat bahwa keyword atau kata kunci yang diekstrak dari teks berita detik diatas bisa menjadi rangkuman isi dari berita. Sepintas kita bisa tahu bahwa artikel diatas merupakan artikel otomotif tentang Toyota Yaris tanpa perlu membaca seluruh isi teks. Hal ini menjadi salah satu kegunaan utama dari aplikasi keyword extraction.
Nah, di blog ini saya akan coba membahas satu teknik ekstraksi kata kunci atau keyword extraction bahasa Indonesia dari dokumen teks. Idenya simpel: kita hanya memperhitungkan kata kunci yang berjenis kata benda atau frasa benda. Dari daftar kata/frasa benda yang kita dapatkan, kita ambil beberapa kata/frasa benda yang penting saja, karena dari sebuah dokumen sangat mungkin kita mendapatkan ratusan kata/frasa benda, dan tidak mungkin kita mengambil semua kata/frasa benda tersebut menjadi kata kunci. Dari sini kita bisa tarik dua pertanyaan besar:
- Bagaimana cara kita mengambil kata/frasa benda dari teks?
- Bagaimana kita mengukur kepentingan dari sebuah kata/frasa benda?
Dua pertanyaan diatas akan saya coba bahas di blog ini.
Implementasi teknik keyword extraction ini saya buat menggunakan Python dalam format Jupyter notebook. Notebook tersebut dapat anda temukan di repo github berikut.
Implementasi¶
Anda memerlukan library python jupyter
, stanfordnlp
, dan nltk
untuk menjalankan proyek ini.
Semua bisa anda install menggunakan pip.
pip install jupyter
pip install stanfordnlp
pip install nltk
Sebelum kita mulai, kita perlu mengunduh file model bahasa Indonesia yang diperlukan untuk menjalankan fungsi stanfordnlp. Buka terminal di komputer anda dan jalankan perintah berikut
python -c "import stanfordnlp;stanfordnlp.download('id')"
Selain itu, kita juga membutuhkan korpus stopwords
dari NLTK
python -m nltk.downloader stopwords
Sekarang kita bisa mulai dengan mengimpor module yang diperlukan
import string
from urllib.request import urlopen
import warnings
import stanfordnlp
import nltk
from nltk.corpus import stopwords
from nltk.util import ngrams
from collections import Counter
from IPython.display import display
warnings.filterwarnings('ignore')
Ekstraksi Frasa Benda / Noun Phrase¶
Untuk mengambil frasa benda dari teks, kita memerlukan library stanfordnlp
.
Yang pertama perlu kita lakukan untuk menggunakan library stanfordnlp
adalah menginisialisasi pipeline
.
pipeline
dari stanfordnlp
yang sudah kita instansiasi tersebut salah satunya berfungsi sebagai tokenizer,
baik tokenizer kalimat (sentence tokenizer) maupun tokenizer kata (word tokenizer).
Selain tokenizer, pipeline
juga berfungsi menetapkan part-of-speech (POS) atau kelas kata ke tiap token-token yang sudah dipecah sebelumnya oleh tokenizer.
Proses ini lazim dikenal sebagai POS tagging, dan model/algoritma yang menjalankan POS tagging disebut dengan POS tagger.
POS tagging mempunyai peran yang sangat penting karena seperti yang sudah dipaparkan di bagian pembuka, kita hanya memperhitungkan frasa benda sebagai kandidat keyword. POS tagger mampu mengambil frasa benda secara otomatis, yang jika dilakukan secara manual akan sangat memakan waktu.
Omong-omong, stanfordnlp
disini adalah library baru berbasis Python yang menggunakan deep learning sebagai model, berbeda dengan library serupa dari Stanford bernama CoreNLP
yang berbasis Java.
Lumayan, disini kita jadi bisa mencoba library baru ini. Tidak semua fungsi-fungsi CoreNLP
ada di stanfordnlp
, namun pengembang tetap memberikan interface untuk bisa mengakses komponen CoreNLP
melalui stanfordnlp
.
nlp = stanfordnlp.Pipeline(lang='id', processors='tokenize,pos')
Mari kita tes stanfordnlp
menggunakan paragraf sederhana dengan dua kalimat di bawah.
s = """
Pemberi kerja adalah orang perseorangan, pengusaha, badan hukum, atau badan-badan lainnya yang
mempekerjakan tenaga kerja dengan membayar upah atau imbalan dalam bentuk lain.
Pengusaha adalah orang perseorangan, persekutuan, atau badan hukum
yang menjalankan suatu perusahaan milik sendiri.
"""
Kita coba masukkan teks tersebut ke pipeline yang sudah kita buat.
doc = nlp(s.lower())
doc
Disini teks yang dimasukkan menjadi object Document
,
dan tiap kalimat di dalam dokumen sudah dipecah menggunakan sentence tokenizer
yang bisa diakses melalui atribut sentences
. sentences
merupakan list
yang mana tiap elemennya merupakan object Sentence
.
doc.sentences
Word tokenizer dari pipeline bekerja memecah kalimat menjadi kumpulan kata, yang bisa diakses melalui atribut words
. Seperti sentences
, words
merupakan list
, dimana tiap elemennya adalah object Word
.
doc.sentences[1].words
Jika kita perhatikan lebih lanjut, pipeline juga otomatis memberikan POS di tiap token-tokennya.
POS tag bisa diakses melalui atribut upos
di dalam object Word
.
Sangat praktis bukan.
for word in doc.sentences[1].words:
print(word.text, word.upos)
Tahap berikutnya adalah bagaimana kita memilih frasa-frasa yang bisa dianggap sebagai keyword. Kalimat diatas terdiri dari 14 kata (selain tanda baca), artinya terdapat 14 kandidat yang bisa kita perhitungkan untuk menjadi keyword. Daftar kandidat bisa bertambah banyak jika kita juga mempertimbangkan bigram. Kode di bawah mengambil bigram dari kalimat contoh.
words = [word.text for word in doc.sentences[1].words]
bigrams = [
bigram for bigram in list(ngrams(words, 2))
if bigram[0] not in string.punctuation and bigram[1] not in string.punctuation
]
bigrams
Kalimat contoh diatas memiliki 11 bigram, sehingga untuk kalimat tersebut terdapat 35 kandidat yang bisa diperhitungkan sebagai keyword (14 unigram dan 11 bigram). Kalau satu kalimat saja memiliki 35 kandidat untuk keyword, bagaimana dengan satu dokumen teks? Tentunya ukuran daftar kandidat bisa membludak. Untuk memperkecil himpunan keywords yang bisa dipilih, kita menggunakan aturan/rule sederhana:
Hanya frasa benda yang diperhitungkan sebagai kandidat keyword.
Frasa benda adalah frasa yang terdiri dari kata benda secara berurutan dan diikuti oleh kata sifat yang opsional. Disini POS tagger berguna, karena POS tagger lah yang memberikan kelas kata ke setiap token dari sebuah kalimat.
Mengekstrak frasa benda adalah tugas dari parser. Untuk melakukan itu, saya bisa membuat parser kita sendiri, atau menggunakan parser bawaan yang disediakan oleh library nltk
. Saya memilih untuk melakukan yang terakhir. Saya menggunakan RegexpParser
dan membangun grammar sendiri untuk parser menggunakan aturan regex.
Grammarnya begini:
NP (noun phrase atau frasa benda) = NOUN/PROPN+ ADJ*
Atau jika dijabarkan maka frasa benda (NP) dibangun dari satu atau lebih kata benda (NOUN/PROPN), diikuti oleh nol atau lebih ADJ.
Berikut adalah implementasi parser menggunakan NLTK
grammar = "NP: {<NOUN|PROPN>+ <ADJ>*}"
parser = nltk.RegexpParser(grammar)
dan berikut adalah hasil parsing dari parser yang kita buat sebelumnya
word_pos_pairs = [(word.text, word.upos) for word in doc.sentences[0].words]
tree = parser.parse(word_pos_pairs)
print(tree)
Atau jika diilustrasikan dengan gambar
display(tree)
Kode berikut mengambil semua frasa NP dari hasil parsing yang berbentuk tree
keywords = []
for subtree in tree.subtrees():
if subtree.label() == 'NP' and len(subtree.leaves()) >= 1:
words = [item[0] for item in subtree.leaves()]
keywords.append(' '.join(words))
keywords
Disini terlihat bahwa pemberi kerja, orang perseorangan, pengusaha, badan-badan lainnya, tenaga kerja, upah, imbalan, bentuk lain merupakan frasa benda. Kita bisa mengurangi kandidat keyword dari 35 menjadi 9 dengan hanya memperhitungkan frasa benda.
Contoh Ekstraksi Frasa Benda di Dokumen Nyata¶
Kita akan praktekkan teknik ekstraksi di bagian sebelumnya ke dokumen nyata. Saya menggunakan dokumen undang-undang nomor 13 tahun 2003 sebagai contoh. Dokumen undang-undang biasanya cukup panjang dan terkadang sulit dimengerti jika dibandingkan dengan dokumen berita, sehingga dokumen berjenis ini bisa dijadikan contoh konkrit bagaimana keyword extraction bisa membantu kita memahami isi teks tanpa harus membaca dokumen sampai habis. Dokumen ini terdiri dari 20 ribu kata.
Di tahap ini kita coba baca berkas teks dari undang-undang nomor 13 tahun 2003.
url = 'https://raw.githubusercontent.com/bagasabisena/keyword-extraction/master/UU_NO_13_2003.txt'
data = urlopen(url)
text = data.read().decode(encoding='utf-8')
print(text[:1000])
print(len(text.split()))
Selanjutnya kita mencoba untuk mengekstrak frasa benda dari dokumen ini (proses akan memakan waktu agak lama).
doc = nlp(text.lower())
# create word and POS tag pair
pairs = []
for sentence in doc.sentences:
tagged = []
for word in sentence.words:
tagged.append((word.text, word.upos))
pairs.append(tagged)
keywords = []
for sentence in pairs:
parse_tree = parser.parse(sentence)
for subtree in parse_tree.subtrees():
if subtree.label() == 'NP' and len(subtree.leaves()) >= 2: # only consider bigram
words = [item[0] for item in subtree.leaves()]
keywords.append(' '.join(words))
keywords[:20]
len(keywords)
Total kita memiliki 2720 frasa benda yang tidak unik, artinya sebuah frasa benda bisa muncul berkali-kali dalam daftar.
Memilih Frasa Benda yang Penting¶
Di bagian sebelumnya, kita berhasil mengambil frasa benda sejumlah 2720. Lalu bagaimana kita memilih sebagian dari 2720 frasa benda ini sebagai kata kunci? Lagi-lagi saya menggunakan aturan sederhana:
Semakin sering sebuah frasa benda muncul di dokumen, maka semakin penting frasa benda tersebut di dokumen
Disini kita hanya perlu menghitung frekuensi kemunculan frasa benda tersebut di dalam dokumen, lalu mengambil frasa benda dengan nilai frekuensi yang tinggi sebagai kata benda. Pembaca yang familiar dengan statistik TF-IDF akan sadar bahwa disini kita menghitung TF (term frequency) dari frasa benda di dalam dokumen.
Untuk menghitung frekuensi, kita bisa menggunakan Counter
bawaan dari Python
freq = Counter(keywords)
Mari kita lihat 50 keyword paling penting, berdasarkan frekuensi kemunculannya.
freq.most_common(50)
Undang-undang nomor 13 tahun 2003 mengatur tentang ketenegakerjaan. Dari daftar diatas, banyak kata-kata kunci yang relevan dengan topik, misalnya perjanjian kerja, serikat buruh, pemutusan hubungan kerja, dan uang pesangon. Namun beberapa keyword tidak terlalu berkaitan, misalnya huruf a atau bahasa indonesia. Daftar diatas juga memuat keyword yang umum ditemukan di dokumen undang-undang lainnya seperti peraturan pemerintah, tindak pidana dan lembaran negara.
Penutup¶
Teknik sederhana yang dijabarkan di blog ini cukup berhasil untuk mengekstraksi keyword dari teks yang cukup kompleks seperti undang-undang. Minimal dengan mengambil 50 keyword dengan frekuensi terbanyak, kita mampu menyimpulkan bahwa undang-undang nomor 13 tahun 2003 membahas hal-hal yang berkaitan dengan kepegawaian dan perburuhan. Bagusnya lagi, teknik keyword extraction ini tidak memerlukan data yang diberi label alias unsupervised. Namun, perlu diakui bahwa hasil yang didapatkan tidak terlalu bersih dan perlu ada upaya tambahan untuk membuang keyword-keyword 'sampah'.
Diatas saya sempat sekilas membahas tentang TF-IDF. Pemanfaatan TF-IDF merupakan kelanjutan yang logis untuk teknik yang saya gunakan ini, karena kita sudah melakukan setengah proses dari TF-IDF, yakni menghitung komponen TF. Namun untuk mengkalkulasi nilai IDF kita membutuhkan korpus dokumen yang lengkap. Dengan korpus yang lengkap, keyword seperti huruf a atau peraturan menteri bisa dipastikan akan keluar dari daftar karena terkena penalti IDF yang tinggi, mengingat frasa tersebut pasti akan sering disebutkan di banyak dokumen undang-undang.