Ana içeriğe geç

Orta9 dk

Bag-of-words'ten gömmeye

Önkoşul:Tokenization ve BPE

Kanca

  1. derste bag-of-words’ün kelime SIRASINI kaybettiğini gördük. Bu ders, ikinci ve daha derin bir sorunu ortaya çıkarıyor: bag-of-words, kelimeler ARASINDAKİ anlam benzerliğini de HİÇ yakalayamıyor.

Sezgi

Bag-of-words’te her kelime, diğerlerinden tamamen bağımsız bir boyuttur. Bu, “kral” ile “kraliçe”nin, “kral” ile “masa” kadar İLİŞKİSİZ görünmesi demektir — oysa gerçekte kral/kraliçe anlamca çok YAKINDIR.

Mekanizma

Bunu doğrudan ölçelim — kosinüs benzerliği (iki vektörün “aynı yöne bakma” derecesi) ile:

One-hot vektörlerin körlüğü

# 1. derste bag-of-words'ün kelime SIRASINI kaybettiğini gördük. Şimdi ikinci,
# daha derin bir sorununa bakalım: bag-of-words, kelimeler ARASINDAKİ anlam
# benzerliğini de HİÇ yakalamıyor.
kelime_dagarcigi = ["kral", "kraliçe", "masa", "sandalye", "elma"]

def one_hot(kelime, dagarcik):
    v = np.zeros(len(dagarcik))
    v[dagarcik.index(kelime)] = 1
    return v

def kosinus_benzerligi(a, b):
    return np.dot(a, b) / (np.linalg.norm(a) * np.linalg.norm(b) + 1e-12)

print("One-hot vektörlerle 'kral' kelimesinin diğerlerine benzerliği:")
v_kral = one_hot("kral", kelime_dagarcigi)
for k in kelime_dagarcigi:
    v_k = one_hot(k, kelime_dagarcigi)
    print(f"  benzerlik(kral, {k:<10}) = {kosinus_benzerligi(v_kral, v_k):.2f}")

print("\n'kral'-'kraliçe' benzerliği (0.00), 'kral'-'masa' benzerliğiyle (0.00) BİREBİR AYNI!")
print("Oysa kral/kraliçe anlamca YAKIN, kral/masa hiç İLİŞKİSİZ. One-hot/bag-of-words bu farkı GÖREMİYOR.")
print("Neden: her kelime, dağarcıktaki DİĞER kelimelerden bağımsız, kendi başına bir boyuttur.")
One-hot vektörlerle 'kral' kelimesinin diğerlerine benzerliği:
  benzerlik(kral, kral      ) = 1.00
  benzerlik(kral, kraliçe   ) = 0.00
  benzerlik(kral, masa      ) = 0.00
  benzerlik(kral, sandalye  ) = 0.00
  benzerlik(kral, elma      ) = 0.00

'kral'-'kraliçe' benzerliği (0.00), 'kral'-'masa' benzerliğiyle (0.00) BİREBİR AYNI!
Oysa kral/kraliçe anlamca YAKIN, kral/masa hiç İLİŞKİSİZ. One-hot/bag-of-words bu farkı GÖREMİYOR.
Neden: her kelime, dağarcıktaki DİĞER kelimelerden bağımsız, kendi başına bir boyuttur.

“kral”-“kraliçe” benzerliği 0.00 — “kral”-“masa” benzerliğiyle BİREBİR AYNI! Çoğu kişi “sık birlikte geçen kelimeler otomatik olarak benzer sayılır” sanır. Yanlış, çünkü one-hot/bag-of-words vektörlerinde HER kelime kendi ekseni — birbirleriyle hiçbir GEOMETRİK ilişkisi yok.

Matematik

Kosinüs benzerliği ve TF-IDF
benzerlik(a,b)=abab\text{benzerlik}(a, b) = \frac{a \cdot b}{\|a\| \|b\|}TF-IDF(k,d)=TF(k,d)×logNDF(k)\text{TF-IDF}(k, d) = \text{TF}(k,d) \times \log\frac{N}{\text{DF}(k)}
SembolAnlamı
aba \cdot bİki vektörün nokta çarpımı
TF(k,d)\text{TF}(k,d)kk kelimesinin dd belgesindeki göreli sıklığı
DF(k)\text{DF}(k)kk kelimesinin geçtiği belge sayısı; NN toplam belge sayısı

TF-IDF, sık belgede geçen (dolayısıyla az AYIRT EDİCİ) kelimeleri aşağı ağırlıklandırır — ama YİNE DE her kelimeyi kendi ekseninde tutar.

Kod

TF-IDF’in gerçek faydasını görelim, sonra sınırını doğrulayalım:

TF-IDF: ayırt edici kelimeleri öne çıkarmak

# TF-IDF (Term Frequency - Inverse Document Frequency), bag-of-words'ü kısmen
# iyileştirir: SIK belgede geçen (dolayısıyla az ayırt edici) kelimeleri AŞAĞI ağırlıklandırır.
belgeler = [
    "kral ve kraliçe sarayda yaşar",
    "kral ordu ile savaşa gider",
    "kraliçe bahçede çiçek toplar",
]
kelimeler_listesi = [b.split() for b in belgeler]
dagarcik_tfidf = sorted(set(w for kl in kelimeler_listesi for w in kl))

def tf_hesapla(kelimeler, dagarcik):
    sayim = Counter(kelimeler)
    toplam = len(kelimeler)
    return np.array([sayim.get(k, 0) / toplam for k in dagarcik])

def idf_hesapla(kelimeler_listesi, dagarcik):
    N = len(kelimeler_listesi)
    return np.array([np.log(N / sum(1 for kl in kelimeler_listesi if k in kl)) for k in dagarcik])

idf = idf_hesapla(kelimeler_listesi, dagarcik_tfidf)
print(f"\n3 belgelik bir corpus'ta 'kral' ve 'kraliçe' 2 belgede geçiyor (IDF düşük);")
print("'sarayda', 've', 'yaşar' gibi kelimeler SADECE 1 belgede geçiyor (IDF yüksek).")

for i, kl in enumerate(kelimeler_listesi):
    tf = tf_hesapla(kl, dagarcik_tfidf)
    tfidf = tf * idf
    en_yuksek = sorted(zip(dagarcik_tfidf, tfidf), key=lambda x: -x[1])[:2]
    print(f"Belge {i+1} en yüksek TF-IDF'li kelimeleri: {[(k, round(v,3)) for k,v in en_yuksek]}")

3 belgelik bir corpus'ta 'kral' ve 'kraliçe' 2 belgede geçiyor (IDF düşük);
'sarayda', 've', 'yaşar' gibi kelimeler SADECE 1 belgede geçiyor (IDF yüksek).
Belge 1 en yüksek TF-IDF'li kelimeleri: [('sarayda', np.float64(0.22)), ('ve', np.float64(0.22))]
Belge 2 en yüksek TF-IDF'li kelimeleri: [('gider', np.float64(0.22)), ('ile', np.float64(0.22))]
Belge 3 en yüksek TF-IDF'li kelimeleri: [('bahçede', np.float64(0.275)), ('toplar', np.float64(0.275))]

“kral” ve “kraliçe” 2 belgede geçtiği için TF-IDF’leri DÜŞÜK; “sarayda”, “ve” gibi tek-belgelik kelimeler YÜKSEK TF-IDF alıyor — bu, arama motorları için gerçek bir iyileştirme.

Ama kelime benzerliği hâlâ çözülmedi

# TF-IDF, HANGİ belgenin hangi kelimeyi ne kadar 'ayırt edici' kullandığını gösterir --
# ama YİNE DE kelimeler arasındaki ANLAM benzerliğini yakalamaz.
print("\nTF-IDF, 'kral' ve 'kraliçe' kelimelerinin AYRI AYRI vektörlerini karşılaştırdığımızda")
print("hâlâ aynı one-hot mantığını kullanıyor -- kelime düzeyinde benzerlik SORUSU hâlâ cevapsız.")
print("TF-IDF, BELGELERİ karşılaştırmak için faydalı (arama motorları gibi) ama KELİMELERİ")
print("anlam uzayında birbirine YAKLAŞTIRMIYOR.")

TF-IDF, 'kral' ve 'kraliçe' kelimelerinin AYRI AYRI vektörlerini karşılaştırdığımızda
hâlâ aynı one-hot mantığını kullanıyor -- kelime düzeyinde benzerlik SORUSU hâlâ cevapsız.
TF-IDF, BELGELERİ karşılaştırmak için faydalı (arama motorları gibi) ama KELİMELERİ
anlam uzayında birbirine YAKLAŞTIRMIYOR.

İhtiyacımız olan: yoğun (dense) vektörler

# İhtiyacımız olan şey: her kelimeyi, ANLAMCA yakın kelimelerin YAKIN, uzak
# kelimelerin UZAK olduğu, YOĞUN (dense) ve DÜŞÜK boyutlu bir vektöre çevirmek.
print(f"\nOne-hot vektör boyutu (dağarcık kadar): {len(kelime_dagarcigi)} -- gerçek bir dağarcıkta 50.000+ olabilir.")
print("Hedeflediğimiz 'embedding' vektörü ise TİPİK OLARAK sadece 100-1000 boyutlu -- ve SEYREK değil YOĞUN.")
print("5. derste (Word Embedding) bu vektörleri NASIL öğrendiğimizi göreceğiz -- öyle ki")
print("'kral' - 'erkek' + 'kadın' ≈ 'kraliçe' gibi ARİTMETİK bile anlamlı hale gelecek.")

One-hot vektör boyutu (dağarcık kadar): 5 -- gerçek bir dağarcıkta 50.000+ olabilir.
Hedeflediğimiz 'embedding' vektörü ise TİPİK OLARAK sadece 100-1000 boyutlu -- ve SEYREK değil YOĞUN.
5. derste (Word Embedding) bu vektörleri NASIL öğrendiğimizi göreceğiz -- öyle ki
'kral' - 'erkek' + 'kadın' ≈ 'kraliçe' gibi ARİTMETİK bile anlamlı hale gelecek.

Nerede işe yarar

Bu dersin çıkarımı, bir sonraki dersin (Word Embedding) TAM olarak neden var olduğunu açıklıyor:

  • TF-IDF, BELGE karşılaştırma görevlerinde (arama, belge sınıflandırma) hâlâ kullanılır — basit, hızlı, yorumlanabilir.
  • Ama “anlam”ı gerektiren görevlerde (çeviri, duygu analizi, soru cevaplama) TF-IDF yetersiz kalır.
  • 5. derste göreceğimiz word embedding’ler, kelimeleri YOĞUN vektörlere çevirip, anlamca yakın kelimeleri geometrik olarak da YAKIN yapacak.

Bu 3 hatayı yaparsın:

  1. TF-IDF’i “akıllı bir anlam analizi” sanmak — aslında sadece İSTATİSTİKSEL sıklık ağırlıklandırması.
  2. One-hot vektörlerin boyutunun, gerçek dünyada (50.000+ kelimelik dağarcıklarla) ne kadar İSRAFÇI (çoğu değer sıfır) olduğunu göz ardı etmek.
  3. “Kelime benzerliği” ve “belge benzerliği”ni aynı problem sanmak — TF-IDF ikincisinde iyi, birincisinde YETERSİZ.

Kendini test et

1. Notebook'ta one-hot vektörlerle 'kral'-'kraliçe' benzerliği neden 'kral'-'masa' benzerliğiyle AYNI (0.00) çıktı?
  1. Kral ve kraliçe kelimeleri aslında ilişkisizdir
  2. One-hot vektörlerde her kelime kendi bağımsız eksenidir -- vektörler arasında ANLAM temelli hiçbir geometrik ilişki tanımlı değildir, sadece "aynı kelime mi değil mi" bilgisi vardır (doğru cevap)
  3. Kod hatalıydı
  4. Kosinüs benzerliği yanlış hesaplandı

Neden: One-hot temsilde her kelime, diğerlerinden bağımsız TEK bir boyuta karşılık gelir; bu yüzden farklı iki kelimenin vektörleri her zaman dik (kosinüs benzerliği 0) olur -- ANLAMCA ne kadar yakın olduklarından bağımsız.

2. TF-IDF, bag-of-words'e göre ne KAZANDIRIYOR?
  1. Kelimeler arasındaki anlam benzerliğini çözüyor
  2. Sık belgede geçen (dolayısıyla az ayırt edici) kelimeleri aşağı ağırlıklandırıp, bir belgeyi AYIRT EDEN kelimeleri öne çıkarıyor (doğru cevap)
  3. Kelime sırası sorununu çözüyor
  4. Hiçbir şey kazandırmıyor

Neden: TF-IDF, IDF terimiyle çok belgede geçen kelimeleri (az bilgi taşırlar) aşağı, az belgede geçen kelimeleri (o belgeye özgü, ayırt edici) yukarı ağırlıklandırır -- bu, belge karşılaştırma görevlerinde faydalıdır.

3. Bu dersin sonucuna göre, bir sonraki derste (Word Embedding) hangi problem çözülecek?
  1. Kelime sırası problemi
  2. Kelimeleri, anlamca yakın olanların birbirine YAKIN, uzak olanların UZAK olduğu, yoğun (dense) ve düşük boyutlu vektörlere çevirme problemi (doğru cevap)
  3. Noktalama işaretleri problemi
  4. Büyük/küçük harf problemi

Neden: Bu ders, one-hot/TF-IDF'in kelime ANLAMI benzerliğini yakalayamadığını gösterdi; word embedding'ler, kelimeleri anlam uzayında birbirine göre konumlandıran yoğun vektörler öğrenerek bu boşluğu dolduracak.

Özet

Özet

  • One-hot/bag-of-words vektörlerinde her kelime bağımsız bir eksendir -- farklı kelimelerin kosinüs benzerliği HER ZAMAN sıfırdır.
  • Bu, anlamca yakın kelimelerin (kral/kraliçe) bile hiç ilişkisiz kelimeler (kral/masa) kadar "uzak" görünmesine yol açar.
  • TF-IDF, belge karşılaştırma görevlerinde faydalı bir iyileştirmedir ama kelime ANLAMI benzerliğini çözmez.
  • İhtiyaç duyulan şey: kelimeleri yoğun (dense), düşük boyutlu, anlamı geometrik olarak kodlayan vektörlere çevirmek.
  • Bu, 5. dersin (Word Embedding) konusu -- öyle bir uzay ki "kral - erkek + kadın ≈ kraliçe" gibi aritmetik bile anlamlı olacak.
Sonraki adım: Word embedding (Word2Vec, GloVe) →