Bag of words

Representasi dokumen sebagai hitungan kata dengan kosakata sebagai ruang fitur.

Daftar isi

Bag of words adalah cara paling sederhana untuk mengubah dokumen menjadi angka yang dapat diolah model: urutan kata diabaikan, dan yang tersimpan hanyalah banyaknya kemunculan setiap kata. Topik ini membahas pembentukan representasi tersebut dengan CountVectorizer dari scikit-learn, cara membaca matriks hitungan yang dihasilkan, serta kelemahan yang melatarbelakangi pembobotan TF-IDF. Setelah membacanya, struktur vektor dokumen dapat dijelaskan melalui contoh yang dapat dijalankan ulang.

Dokumen sebagai vektor hitungan#

Model bag of words merepresentasikan satu dokumen sebagai vektor dengan panjang sebesar kosakata, yaitu himpunan semua kata berbeda pada korpus. Nilai pada setiap komponen vektor adalah hitungan kemunculan kata tersebut di dalam dokumen. Korpus berisi enam dokumen pendek dapat menghasilkan kosakata berukuran 38 kata, sehingga setiap dokumen menjadi vektor dengan 38 komponen. Kata yang tidak muncul pada suatu dokumen mengisi komponennya dengan angka nol.

Menurut pandangan ini, makna dokumen ditentukan oleh kata mana yang muncul dan berapa kali kemunculannya, bukan oleh urutannya. Kalimat “ombak besar menghadirkan pemandangan indah” dan “indah menghadirkan besar ombak pemandangan” menghasilkan vektor yang sama persis. Penyederhanaan ini terasa kasar, tetapi ukuran kehadiran kata ternyata cukup untuk banyak tugas, misalnya membedakan ulasan film positif dari ulasan negatif. Istilah bag of words menggambarkan pandangan tersebut secara harfiah, yaitu dokumen diperlakukan seperti kantong berisi kata yang diacak.

Demo CountVectorizer pada korpus kecil#

Program berikut membentuk matriks hitungan dari enam dokumen sintetis, yaitu tiga catatan perjalanan dan tiga catatan resep masakan. CountVectorizer menurunkan huruf menjadi kecil, membuang tanda baca, membagi teks menjadi token, lalu menghitung kemunculan setiap token. Simpan programnya sebagai bag_of_words_demo.py dan jalankan dengan perintah python3 bag_of_words_demo.py.

python bag_of_words_demo.py
import warnings

warnings.filterwarnings("ignore")

from sklearn.feature_extraction.text import CountVectorizer

dokumen = [
    "hari pertama di pantai ombak besar udara sejuk",
    "hari kedua di bandung udara sejuk jalan kaki",
    "hari ketiga di museum sejarah kota lama",
    "resep sup ayam kuah bening garam dan merica",
    "resep nasi goreng bawang putih dan kecap manis",
    "cara memasak rendang daging santan dan lama api kecil",
]

vektor = CountVectorizer()
X = vektor.fit_transform(dokumen)

nama = vektor.get_feature_names_out()
print("Kosakata (urut abjad):")
for i in range(0, len(nama), 8):
    print(" ".join(f"{k:<10}" for k in nama[i : i + 8]))

print()
print("Ukuran matriks:", X.shape)
print()
print("Matriks hitungan (baris = dokumen, kolom = kata):")
print(X.toarray())
text Keluaran
Kosakata (urut abjad):
api        ayam       bandung    bawang     bening     besar      cara       daging    
dan        di         garam      goreng     hari       jalan      kaki       kecap     
kecil      kedua      ketiga     kota       kuah       lama       manis      memasak   
merica     museum     nasi       ombak      pantai     pertama    putih      rendang   
resep      santan     sejarah    sejuk      sup        udara     

Ukuran matriks: (6, 38)

Matriks hitungan (baris = dokumen, kolom = kata):
[[0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0 0 0 0 0 1
  0 1]
 [0 0 1 0 0 0 0 0 0 1 0 0 1 1 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
  0 1]
 [0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 1 1 0 1 0 0 0 1 0 0 0 0 0 0 0 0 1 0
  0 0]
 [0 1 0 0 1 0 0 0 1 0 1 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0
  1 0]
 [0 0 0 1 0 0 0 0 1 0 0 1 0 0 0 1 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 1 0 0 0
  0 0]
 [1 0 0 0 0 0 1 1 1 0 0 0 0 0 0 0 1 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0
  0 0]]

Keluaran menunjukkan kosakata berukuran 38 kata yang diurutkan menurut abjad dan matriks berukuran (6, 38). Matriks memuat enam baris dengan 38 angka pada tiap baris, dan sebagian besar angkanya nol. Pola seperti itu wajar karena dokumen pendek hanya menyentuh sebagian kecil dari seluruh kosakata.

Baris dokumen, kolom kata#

Matriks hitungan memiliki struktur tetap, yaitu setiap baris mewakili satu dokumen dan setiap kolom mewakili satu kata dari kosakata. Diagram berikut memperlihatkan pemetaan dua dokumen pertama ke dalam vektornya dengan delapan kolom kosakata sebagai percontohan.

Dokumen 0hari pertama di pantaiombak besar udara sejukDokumen 1hari kedua di bandungudara sejuk jalan kakiKosakatabandungdiharijalankakiombakudarasejuk… 38 kata …Vektor hitungan[0 1 1 0 0 1 1 1][1 1 1 1 1 0 1 1]
Pemetaan dokumen ke vektor hitungan

Membaca matriks kini tinggal soal koordinat. Baris pertama bernilai 1 pada kolom di, hari, ombak, dan udara karena keempat kata itu muncul satu kali pada dokumen 0. Kolom di bernilai 1 pada tiga baris pertama karena ketiga catatan perjalanan memuatnya, sedangkan kolom dan bernilai 1 pada tiga baris terakhir milik catatan resep. Kolom lama bernilai 1 pada baris ketiga dan keenam, sehingga menjadi satu-satunya kata pada contoh ini yang melintasi kedua tema.

Kelemahan bag of words#

Tiga kelemahan melekat pada representasi ini. Pertama, urutan kata hilang sepenuhnya sehingga negasi menjadi masalah, sebab kalimat hasilnya tidak bagus berubah menjadi hitungan kata yang tidak lagi menunjukkan bahwa bagus sedang dinegasikan. Fitur n-gram memulihkan sebagian urutan dengan menambahkan pasangan kata berurutan sebagai kolom baru.

Kedua, matriksnya jarang (sparse). Dokumen hanya memuat sebagian kecil kosakata, sehingga hampir semua sel matriks berisi nol. scikit-learn menyimpan matriks ini dalam format sparse yang hanya menyimpan sel tidak nol, dan metode toarray() pada demo di atas aman dipanggil hanya karena datanya kecil. Ketiga, jumlah kolom tumbuh mengikuti kosakata. Setiap kata baru pada korpus menambah satu kolom, sehingga korpus nyata yang berisi ribuan dokumen mudah menghasilkan puluhan ribu kolom. Kosakata yang besar membuat matriks makin tipis sekaligus makin berat dihitung, dan kata yang muncul sekali saja sering tidak membantu model apa pun.

Kesalahan umum#

Tiga kesalahan berikut muncul berulang ketika representasi ini pertama kali dipraktikkan.

  • Mengonversi matriks besar dengan toarray(). Konversi tersebut mengalokasikan memori sebesar jumlah baris dikali jumlah kolom, misalnya 2000 dokumen dengan 35000 kata menghasilkan 70 juta sel. Simpan matriks dalam bentuk sparse dan lakukan perhitungan langsung padanya.
  • Mengasumsikan tanda baca dan huruf kapital ikut dihitung. CountVectorizer menurunkan huruf dan membuang tanda baca melalui pola token default, tetapi pola yang sama juga membuang token satu huruf. Kata satu huruf pada teks lenyap tanpa peringatan, sedangkan kata dua huruf seperti di tetap ada.
  • Menambahkan kosakata baru setelah fit_transform dijalankan. Kosakata dibekukan pada saat fit_transform berjalan, sehingga transform terhadap dokumen baru yang memuat kata asing akan mengabaikan kata itu tanpa error. Apabila korpus berubah signifikan, jalankan ulang metode fit pada vektorisator dari awal.

Ringkasan#

  • Dokumen direpresentasikan sebagai vektor hitungan dengan panjang sebesar kosakata, dan korpus menjadi matriks berukuran jumlah dokumen kali jumlah kata.
  • CountVectorizer menurunkan huruf, membuang tanda baca, membuang token satu huruf, dan tetap menyimpan kata fungsi karena tidak menyaring stop word secara default.
  • Kelemahan utamanya berupa urutan kata yang hilang, matriks yang jarang, dan jumlah kolom yang tumbuh mengikuti kosakata.

Referensi#