TF-IDF

Pembobotan ulang hitungan kata berdasarkan kelangkaan kata di seluruh korpus.

Daftar isi

TF-IDF (term frequency-inverse document frequency) menimbang ulang hitungan kata dengan memperhatikan kelangkaannya di seluruh korpus: kata yang muncul di banyak dokumen diberi bobot kecil, sedangkan kata yang khas hanya pada beberapa dokumen diberi bobot besar. Topik ini merinci komponen TF dan IDF beserta rumusnya, mendemokan TfidfVectorizer pada korpus yang sama dengan demo bag of words, dan menjelaskan parameter pentingnya. Setelah membacanya, bobot pada keluaran program dapat dijelaskan langsung dari rumusnya.

Mengapa hitungan mentah kurang tepat#

Dalam matriks bag of words, kata yang muncul di hampir semua dokumen dan kata yang khas mendapat perlakuan yang sama. Pada korpus enam catatan perjalanan dan resep, kata di muncul di ketiga catatan perjalanan tanpa memberi petunjuk khusus tentang isi, sedangkan kata ombak muncul sekali dan langsung menunjuk catatan pantai. Model yang memakai hitungan mentah harus menemukan perbedaan itu sendiri dari data latih. Pembobotan TF-IDF menyimpan pengetahuan tersebut ke dalam nilai fitur, sehingga model klasifikasi maupun pemeringkat tidak perlu menemukannya lagi.

Perlu dicatat bahwa kata umum tidak selalu tidak berguna. Bobotnya hanya diredam, bukan dihapus, karena kata fungsi tetap dapat menjadi sinyal gaya penulisan pada tugas tertentu. Pembobotan ini memindahkan penilaian tentang kata yang menonjol dari intuisi ke statistik korpus, yaitu frekuensi dokumen (document frequency atau df) yang dihitung untuk setiap kata.

Komponen TF dan IDF#

Komponen pertama mengukur kehadiran kata di dalam dokumen. Nilai tf⁡(t,d)\operatorname{tf}(t, d) adalah banyaknya kemunculan kata tt pada dokumen dd, dalam hitungan mentah sebagaimana matriks bag of words. Komponen kedua mengukur kelangkaan kata di seluruh korpus. scikit-learn menghitungnya dengan rumus berikut.

idf⁡(t)=ln⁡1+n1+df⁡(t)+1 \operatorname{idf}(t) = \ln\frac{1 + n}{1 + \operatorname{df}(t)} + 1

Dalam rumus tersebut, nn adalah jumlah dokumen pada korpus dan df⁡(t)\operatorname{df}(t) adalah jumlah dokumen yang memuat kata tt. Penambahan 1 pada pembilang dan penyebut disebut smooth idf dan aktif secara default melalui parameter smooth_idf=True. Tanpa peredaman ini, kata yang muncul di seluruh korpus mendapatkan idf bernilai nol sehingga kontribusinya hilang total, sedangkan dengan peredaman idf-nya tetap bernilai 1. Kedua komponen kemudian digabungkan menjadi bobot.

tfidf⁡(t,d)=tf⁡(t,d)×idf⁡(t) \operatorname{tfidf}(t, d) = \operatorname{tf}(t, d) \times \operatorname{idf}(t)

Langkah terakhir adalah normalisasi L2 terhadap setiap vektor dokumen, yaitu membagi setiap bobot dengan panjang vektornya (norma L2). Panjang vektor dokumen menjadi 1, sehingga dokumen yang panjang dan menumpuk banyak kata tidak otomatis mendapat skor besar. Normalisasi ini aktif secara default melalui parameter norm="l2".

Demo TfidfVectorizer pada korpus yang sama#

Program berikut memakai enam dokumen catatan perjalanan dan resep yang sama dengan demo bag of words. Program mencetak nilai df dan IDF untuk delapan kata terpilih, lalu mencetak bobot TF-IDF kedelapan kata tersebut pada setiap dokumen. Simpan programnya sebagai tfidf_demo.py dan jalankan dengan perintah python3 tfidf_demo.py.

python tfidf_demo.py
import warnings

warnings.filterwarnings("ignore")

import numpy as np
import pandas as pd
from sklearn.feature_extraction.text import TfidfVectorizer

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 = TfidfVectorizer()
X = vektor.fit_transform(dokumen)

pilihan = ["dan", "di", "hari", "udara", "sejuk", "lama", "ombak", "santan"]
kolom = [vektor.vocabulary_[k] for k in pilihan]

print("Frekuensi dokumen (df) dan bobot IDF delapan kata terpilih:")
for k in pilihan:
    i = vektor.vocabulary_[k]
    df = int((X[:, i] > 0).sum())
    print(f"{k:<8} df={df}  idf={vektor.idf_[i]:.3f}")

print()
print("Bobot TF-IDF untuk delapan kata terpilih (baris = dokumen):")
tabel = pd.DataFrame(np.round(X.toarray()[:, kolom], 3), columns=pilihan)
print(tabel.to_string())
text Keluaran
Frekuensi dokumen (df) dan bobot IDF delapan kata terpilih:
dan      df=3  idf=1.560
di       df=3  idf=1.560
hari     df=3  idf=1.560
udara    df=2  idf=1.847
sejuk    df=2  idf=1.847
lama     df=2  idf=1.847
ombak    df=1  idf=2.253
santan   df=1  idf=2.253

Bobot TF-IDF untuk delapan kata terpilih (baris = dokumen):
     dan     di   hari  udara  sejuk   lama  ombak  santan
0  0.000  0.276  0.276  0.327  0.327  0.000  0.398    0.00
1  0.000  0.276  0.276  0.327  0.327  0.000  0.000    0.00
2  0.000  0.292  0.292  0.000  0.000  0.346  0.000    0.00
3  0.259  0.000  0.000  0.000  0.000  0.000  0.000    0.00
4  0.259  0.000  0.000  0.000  0.000  0.000  0.000    0.00
5  0.242  0.000  0.000  0.000  0.000  0.287  0.000    0.35

Membaca bobot kata#

Bagian IDF pada keluaran mengikuti rumus dengan tepat. Kata dan, di, dan hari muncul di tiga dari enam dokumen sehingga idf-nya 1.560, kata udara, sejuk, dan lama muncul di dua dokumen dengan idf 1.847, sedangkan kata ombak dan santan muncul hanya di satu dokumen dengan idf 2.253. Semakin langka kata di korpus, semakin besar nilai idf-nya.

Tabel bobot menunjukkan efek gabungan kedua komponen. Pada dokumen 0, semua kata terpilih hanya muncul satu kali sehingga komponen tf-nya setara, tetapi bobot ombak sebesar 0.398 mengungguli udara sebesar 0.327 dan di sebesar 0.276. Urutan bobot mengikuti kelangkaan kata, bukan jumlah kemunculan. Sel yang berisi 0.000 menandakan kata tidak muncul pada dokumen tersebut, dan setiap baris pada matriks penuh memiliki panjang vektor 1 akibat normalisasi L2.

TF-IDF untuk pemeringkatan#

Dalam pencarian dokumen, TF-IDF menjadi dasar pemeringkatan yang paling umum. Dokumen yang memuat kata kueri dengan bobot TF-IDF tinggi mendapat skor lebih besar dibandingkan dokumen yang hanya memuat kata kueri yang umum, sehingga hasil pencarian menonjolkan dokumen yang paling relevan. Vektor TF-IDF juga menjadi fitur masukan yang lazim bagi model klasifikasi teks karena bobotnya menonjolkan kata yang membedakan kelas.

Model pemeringkatan modern mengembangkan ide ini lebih jauh, misalnya dengan BM25 yang menyetel saturasinya terhadap panjang dokumen. BM25 tidak lagi menghitung tf secara linier dan menambahkan penyetelan pada komponen idf-nya. Variasi tersebut dipelajari lebih lanjut pada kurikulum llm-apps, sedangkan jalur ini cukup menempatkan TF-IDF sebagai fondasinya.

Ringkasan#

  • TF mengukur kehadiran kata pada dokumen, sedangkan IDF mengukur kelangkaan kata di seluruh korpus, dan bobot akhirnya adalah hasil kalinya.
  • scikit-learn menghitung idf dengan peredaman smooth idf, yaitu penambahan 1 pada pembilang dan penyebut, dan menormalisasi setiap vektor dokumen dengan norma L2 secara default.
  • Kata yang muncul di banyak dokumen memperoleh bobot kecil, sedangkan kata khas per dokumen memperoleh bobot besar, seperti yang tampak pada idf 1.560 untuk kata df=3 dan 2.253 untuk kata df=1.
  • TF-IDF menjadi dasar pemeringkatan dokumen dan fitur lazim bagi model klasifikasi, dengan BM25 sebagai pengembangannya pada pencarian modern.

Referensi#