Hipotesis distribusional

Prinsip bahwa makna kata dapat dikenali dari kata-kata yang kerap menyertainya.

Daftar isi

Hipotesis distribusional adalah dasar dari seluruh embedding kata, yakni representasi makna dalam bentuk vektor angka: prinsipnya, makna sebuah kata dapat dikenali dari kata-kata yang kerap menyertainya. Topik ini memperkenalkan prinsip tersebut, membangun matriks ko-okurensi dari jendela konteks geser, dan menghitung kemiripan dua kata langsung dari baris matriksnya dengan Python. Setelah membaca topik ini, kemiripan makna antarkata dapat dibaca dari angka, bukan dari intuisi semata.

Prinsip Firth: makna dikenali dari temannya#

Linguis J.R. Firth merumuskan gagasan ini dengan kalimat yang sering dikutip: kata dikenali dari teman-temannya (You shall know a word by the company it keeps). Kata buku dan kata koran, misalnya, sama-sama mendampingi kata membaca, meminjam, dan menata. Keduanya sama-sama benda yang dibaca manusia, dan pola kemunculannya menunjukkan hal itu sebelum ada definisi apa pun yang dituliskan.

Hipotesis distribusional, yang diperkenalkan dalam linguistik komputasional melalui karya Zellig Harris, mengubah prinsip tersebut menjadi prosedur terukur. Langkahnya tiga tahap: hitung konteks setiap kata, bandingkan profil konteks antarkata, lalu perlakukan dua kata dengan profil serupa sebagai kata yang maknanya berdekatan. Prosedur ini tidak memerlukan kamus maupun label buatan manusia. Satu-satunya bahan bakunya adalah teks mentah dan definisi tetangga yang jelas, sehingga prinsip ini dapat dijalankan pada korpus apa pun tanpa kerja anotasi. Ketentuan itu juga menjelaskan apa yang tidak terjadi: pasangan kata yang tidak pernah bertemu dalam satu jendela, seperti buku dan pensil pada demo di bawah, tidak akan mendekat satu sama lain meski keduanya sama-sama benda yang berhubungan dengan sekolah.

Matriks ko-okurensi dari jendela geser#

Matriks ko-okurensi menyimpan profil konteks tersebut dalam bentuk tabel. Setiap baris milik satu kata, setiap kolom milik satu kata lain, dan setiap sel mencatat berapa kali dua kata itu muncul bersama dalam satu jendela (window), yakni rentang tetangga tertentu di sekitar kata pusat. Jendela berukuran 2 berarti dua kata di kiri dan dua kata di kanan kata pusat ikut dihitung. Jendela digeser kata demi kata hingga seluruh kalimat terbaca, lalu proses yang sama dijalankan pada semua kalimat korpus. Matriksnya berukuran jumlah kata pada kedua dimensinya, sehingga korpus dengan kosakata besar menghasilkan tabel raksasa yang sebagian besar selnya bernilai nol.

Diagram berikut menangkap satu posisi jendela pada kalimat contoh, dengan kata buku sebagai kata pusatnya.

jendela konteks (ukuran 2)mahasiswamembacabukudiperpustakaankata pusatsetiap tetangga dalam jendelamenambah satu hitunganpada baris kata pusat
Jendela konteks ukuran 2 pada kalimat contoh

Dalam diagram itu, tetangga kanan buku adalah membaca dan di, sehingga satu posisi jendela ini menambah hitungan pada pasangan buku-membaca dan buku-di. Sisi kiri jendela mencapai mahasiswa, sehingga pasangan buku-mahasiswa ikut bertambah. Setiap pergeseran berikutnya mengulang pencatatan yang sama pada kata pusat yang baru, dan matriks akhirnya menyimpan statistik ko-okurensi seluruh korpus.

Demo Python: dari kalimat ke kemiripan#

Skrip berikut membangun matriks ko-okurensi dari sepuluh kalimat sintetis bertema sekolah, menghitung kemiripan antarbarisnya, lalu membandingkan dua pasang kata yang teman-temannya berbeda. Pasangannya dipilih untuk menguji hipotesis secara langsung: buku dan koran berbagi hampir semua tetangganya, sedangkan pensil hanya berbagi sedikit.

python matriks_ko_okurensi.py
import numpy as np

korpus = [
    "mahasiswa membaca buku di perpustakaan",
    "mahasiswa membaca koran di perpustakaan",
    "guru membaca buku di kelas",
    "guru membaca koran di kelas",
    "guru membaca koran di kantor",
    "mahasiswa meminjam buku dari rak",
    "mahasiswa meminjam koran dari rak",
    "penjaga menata buku di rak",
    "mahasiswa membeli pensil di kantin",
    "guru membeli pensil di kantin",
]

kalimat_token = [k.split() for k in korpus]
kosakata = sorted({t for k in kalimat_token for t in k})
indeks = {t: i for i, t in enumerate(kosakata)}

ukuran_jendela = 2
M = np.zeros((len(kosakata), len(kosakata)), dtype=int)
for token in kalimat_token:
    for pos, kata in enumerate(token):
        i = indeks[kata]
        awal = max(0, pos - ukuran_jendela)
        akhir = min(len(token), pos + ukuran_jendela + 1)
        for pos_tetangga in range(awal, akhir):
            if pos_tetangga == pos:
                continue
            j = indeks[token[pos_tetangga]]
            M[i, j] += 1

for i, kata in enumerate(kosakata):
    print(i, kata)
print()
print(M)

def kosinus(u, v):
    return u @ v / (np.linalg.norm(u) * np.linalg.norm(v))

buku = M[indeks["buku"]].astype(float)
koran = M[indeks["koran"]].astype(float)
pensil = M[indeks["pensil"]].astype(float)

print()
print("buku · koran : dot =", buku @ koran, ", kosinus =", round(kosinus(buku, koran), 3))
print("buku · pensil: dot =", buku @ pensil, ", kosinus =", round(kosinus(buku, pensil), 3))
text Keluaran
0 buku
1 dari
2 di
3 guru
4 kantin
5 kantor
6 kelas
7 koran
8 mahasiswa
9 membaca
10 membeli
11 meminjam
12 menata
13 penjaga
14 pensil
15 perpustakaan
16 rak

[[0 1 3 1 0 0 1 0 2 2 0 1 1 1 0 1 2]
 [1 0 0 0 0 0 0 1 0 0 0 2 0 0 0 0 2]
 [3 0 0 0 2 1 2 3 0 5 2 0 1 0 2 2 1]
 [1 0 0 0 0 0 0 2 0 3 1 0 0 0 1 0 0]
 [0 0 2 0 0 0 0 0 0 0 0 0 0 0 2 0 0]
 [0 0 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
 [1 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
 [0 1 3 2 0 1 1 0 2 3 0 1 0 0 0 1 1]
 [2 0 0 0 0 0 0 2 0 2 1 2 0 0 1 0 0]
 [2 0 5 3 0 0 0 3 2 0 0 0 0 0 0 0 0]
 [0 0 2 1 0 0 0 0 1 0 0 0 0 0 2 0 0]
 [1 2 0 0 0 0 0 1 2 0 0 0 0 0 0 0 0]
 [1 0 1 0 0 0 0 0 0 0 0 0 0 1 0 0 0]
 [1 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0]
 [0 0 2 1 2 0 0 0 1 0 2 0 0 0 0 0 0]
 [1 0 2 0 0 0 0 1 0 0 0 0 0 0 0 0 0]
 [2 2 1 0 0 0 0 1 0 0 0 0 0 0 0 0 0]]

buku · koran : dot = 27.0 , kosinus = 0.902
buku · pensil: dot = 9.0 , kosinus = 0.455

Baris buku dan baris koran memuat hitungan yang hampir identik: keduanya kerap muncul bersama membaca, meminjam, mahasiswa, di, rak, perpustakaan, dan kelas. Perbedaannya tipis, yaitu kantor, guru, dan membaca sedikit lebih banyak di sisi koran, sedangkan penjaga, menata, dan rak sedikit lebih banyak di sisi buku. Profil hampir sama itu terbaca langsung dari hasil akhirnya: kosinus buku-koran mencapai 0.902. Baris pensil hanya berbagi di, guru, dan mahasiswa dengan buku, sehingga kosinusnya turun ke 0.455.

Dari hitungan mentah ke sudut#

Perbandingan pada demo memakai dua ukuran yang berbeda. Perkalian titik (dot product) menjumlahkan hasil kali komponen dua vektor, yaitu ∑kukvk\sum_k u_k v_k, sedangkan kemiripan kosinus membaginya dengan panjang kedua vektor:

kosinus⁡(u,v)=u⋅v∥u∥ ∥v∥ \operatorname{kosinus}(\mathbf{u}, \mathbf{v}) = \frac{\mathbf{u} \cdot \mathbf{v}}{\|\mathbf{u}\| \, \|\mathbf{v}\|}

Kosinus menghilangkan pengaruh panjang vektor. Kata yang sangat sering muncul mendapat baris dengan angka besar di banyak sel, sehingga perkalian titiknya terhadap kata lain cenderung tinggi tanpa makna tambahan. Pembagian oleh panjang menormalkan ketidaksetaraan itu dan menyisakan arah semata, sehingga dua kata jarang yang tetangganya mirip tetap dapat memperoleh skor tinggi. Pada demo, pasangan 0.902 terhadap 0.455 memberi urutan yang tegas: profil konteks buku jauh lebih dekat ke koran daripada ke pensil.

Semua hitungan pada demo bernilai tak negatif, sehingga kosinusnya hanya mungkin berada di antara 0 dan 1. Rentang terbatas itu tetap memberi peringkat kemiripan yang jelas, dan peringkat inilah yang dibaca ketika menilai keluaran model embedding. Skor kosinus tidak pernah diperlakukan sebagai probabilitas, melainkan ukuran sudut antara dua arah semata.

Kesalahan umum#

  1. Membandingkan kata dengan perkalian titik mentah. Panjang vektor kata berfrekuensi tinggi lebih besar, sehingga perkalian titiknya terhadap semua kata ikut naik dan perbandingan menjadi bias. Gunakan kosinus apabila tujuannya mengukur kemiripan antarkata.
  2. Menganggap baris matriks ko-okurensi sebagai embedding final. Barisnya berdimensi sebanyak kosakata dan sebagian besar selnya kosong, sehingga boros memori dan tidak praktis sebagai fitur. Baris matriks ini adalah bahan baku, sedangkan embedding padat diperoleh setelah dimensinya dipadatkan oleh model seperti word2vec.
  3. Menetapkan ukuran jendela tanpa mempertimbangkan tujuan. Jendela sempit menangkap hubungan sintaksis antarkata yang berdekatan, sedangkan jendela lebar menangkap kesamaan tema. Pilih ukuran jendela sesuai jenis kemiripan yang ingin ditangkap, bukan sekadar mengikuti nilai default.

Ringkasan#

  • Hipotesis distribusional menyatakan bahwa makna kata dikenali dari kata-kata yang kerap menyertainya.
  • Matriks ko-okurensi jendela geser mengubah prinsip itu menjadi angka: baris untuk kata pusat, kolom untuk tetangga, dan sel untuk hitungan kemunculan bersama.
  • Pada demo sepuluh kalimat, kosinus buku-koran mencapai 0.902 sedangkan buku-pensil hanya 0.455, sesuai tingkat kemiripan teman-temannya.
  • Kosinus lebih tepat daripada perkalian titik karena menghilangkan pengaruh panjang vektor akibat perbedaan frekuensi kata.

Referensi#