---
title: 'Metin Sınıflandırma'
source: 'https://academia.sh/tr/kurslar/nlp-ve-goru/metin-siniflandirma'
course: 'Doğal Dil İşleme ve Bilgisayarla Görme'
language: tr
updated: '2026-08-17T18:10:15+00:00'
license: 'CC BY-SA 4.0'
---

# Metin Sınıflandırma

Bir saha notunun bütününe tek bir olay türü kararı verilmesi ve boru hattının üç adımının her birinin kaç puan kattığının ayrı ayrı sayılması: en sık sınıf tabanı 0,4420, elle sayılmış yedi ölçü 0,5500, sözcük torbası ve doğrusal model 0,9620. On iki kurulum üzerinde ölçüldüğünde temsil adımı ortalama 0,3787, sınıflandırıcı adımı 0,0500, terim ağırlıklandırma 0,0140 katıyor; belirteçleme kararlarının ikisi de eksi katkı veriyor ve ek kırpma sözlüğü 109'dan 89'a indirirken ortalama 0,0165 kaybettiriyor. Bir adımın katkısı tek bir sayı değildir: ağırlıklandırma sınıf ortalamasıyla 0,0340'a çıkarken doğrusal modelle 0,0060 eksiye iniyor.

Dört derste metin sayıya çevrildi. Belirteçleme kararının sözlük boyunu nasıl oynattığı, sözcük
torbasının ve terim ağırlıklandırmanın elle sayılmış özniteliklere ne kattığı, gömmenin bağlamdan
nasıl öğrenildiği ve etiketlerin **belirteçlere** nasıl dağıtıldığı ölçüldü. Bütün bu ölçümlerde
karar biriminin altı belirteçti: her belirteç kendi etiketini aldı, ölçüt belirteç ya da varlık
düzeyinde okundu.

Belgenin **bütününe** tek bir karar vermek hiç denenmedi. Bir saha notu okunur ve dört olay
türünden biri yazılır: sayaç arızası, kaçak şüphesi, erişilemedi, olağan. Bu kurulumda çıktı tek
bir etikettir ve girdinin uzunluğu değişkendir. Bu dersin sorusu şudur: bu kararı üreten boru
hattının **hangi adımı kaç puan katıyor**. Adımlar üçtür — belirteçleme, terim ağırlıklandırma,
sınıflandırıcı — ve her birinin katkısı ötekilerinden bağımsız değildir.

- **NL41.** Saha notları **kurgudur**. M27/K02 `oznitelik-secimi/02`'nin ürettiği not alanının
  genişletilmiş hâlidir: her not bir olay öbeğinden, kimi zaman başka bir türden ödünç alınmış bir
  yan kayıttan, bir gürültü ifadesinden ve bir hat işaretinden kurulur. Tohum 20260218.
- **NL42.** Olay türü etiketi notun **üretildiği türdür**, notun içindeki sözcüklerden türetilmez.
  Ödünç alınan yan kayıt yüzünden metin kimi zaman başka bir türü işaret eder; bu ölçünün tavanını
  aşağı çeker ve kurgunun kasıtlı bir parçasıdır.
- **NL43.** Küme 1.600 nottur; ilk 1.100'ü eğitim, son 500'ü ayrılmış kümedir.
- **NL44.** **Alanın tabanı en sık sınıftır.** Dört sınıflı bir görevde rastgele atama 0,25
  dolayında kalır; en sık sınıf bundan yüksektir ve sınıflar dengesiz olduğu için
  asıl karşılaştırma odur.
- **NL45.** Boru hattının **her adımı yalnız eğitim kümesinden öğrenilir**: sözlük,
  belge sıklıkları ve model ağırlıkları. Bu kural M27/K02 `oznitelik-secimi/05`'te kuruldu
  ve burada sürer.
- **NL46.** Sözlüğe eğitim kümesinde **en az iki notta** geçen sözcükler alınır.
- **NL47.** İki sınıflandırıcı da ders içinde yazılır ve **modeldir**: sınıf ortalaması
  (her sınıfın ortalama vektörüne açı benzerliği) ve dört sınıflı doğrusal model.

## Belgenin Bütününe Tek Karar

Sınıflandırmanın girdisi bir belgedir, çıktısı bir etikettir. Dizi etiketlemeden farkı bir ölçek
farkı değil, bir karar birimi farkıdır: orada her belirteç için bir çıktı vardı, burada bütün not
için bir çıktı vardır ve notun kaç belirteçten oluştuğu çıktının biçimini değiştirmez.

```python
# KURGU saha notlari — M27/K02'nin not alaninin genisletilmis hali. Tohum 20260218.
import math

TOHUM, M32 = 20260218, 0xFFFFFFFF
TUR = ("olagan", "erisilemedi", "sayac arizasi", "kacak suphesi")
PAY = (0.46, 0.22, 0.19, 0.13)
OBEK = {t: s.split("|") for t, s in zip(TUR, (
    "okuma normal|okuma normaldi|sayac erisimi saglandi|sayaca erisildi|olcum tekrarlandi|"
    "olcumu yineledik|vana kontrol edildi|vanada sorun yok|kapak temiz|kapakta iz yok|"
    "gosterge okunakli|gostergede rakam net",
    "abone evde degildi|abone bulunamadi|erisim saglanamadi|erisim yok|kapi zili calismiyor|"
    "zil calismadi|bahce kapisi kilitli|bahce kapisi kapali|bodrum katina inilemedi|"
    "bodrum kilitli|adres bulunamadi|adres eksik",
    "gosterge donmuyor|gostergede hareket yok|sayac cami kirik|sayacin cami catlak|"
    "rakam okunmuyor|rakamlar silik|ibre sabit kalmis|ibre kilitli|mekanizma takilmis|"
    "mekanizmada takilma|sayac durmus|sayac calismiyor",
    "muhur izi var|muhurde iz goruldu|muhur kopmus|muhurler kopuk|baglanti degistirilmis|"
    "baglantida degisiklik|kelepce gevsek|kelepcede gevseme|boru ek yeri yeni|boruda yeni ek|"
    "sayac ters takilmis|sayaci ters takmislar"))}
GURULTU = ("arac park halinde|kapak kirli|hava yagisli|adres teyit edildi|not kisa tutuldu|"
           "ikinci ziyaret|bahce icinde|kaldirim uzerinde").split("|")
BOLGE = "kuzey hatti|guney hatti|dogu hatti|bati hatti|merkez hatti".split("|")
SUP_P = {"kacak suphesi": 0.86, "sayac arizasi": 0.21, "erisilemedi": 0.07, "olagan": 0.03}


def uretec(t):
    x = ((t ^ (t >> 16)) * 2246822507) & M32
    x = ((x ^ (x >> 13)) * 3266489909) & M32
    s = [(x ^ (x >> 16)) & M32]

    def sonraki():
        s[0] = (s[0] * 1664525 + 1013904223) & M32
        return s[0] / 4294967296
    return sonraki


def not_kur(no):
    r = uretec(TOHUM + 41000 + no)
    u, k = r(), 0.0
    for i, p in enumerate(PAY):
        k += p
        if u < k:
            t = TUR[i]
            break
    p = [OBEK[t][int(r() * 12)]]
    if r() < 0.55:
        p.append(OBEK[t][int(r() * 12)])
    if r() < 0.34:                          # baska turden odunc alinan yan kayit
        p.append(OBEK[TUR[int(r() * 4)]][int(r() * 12)])
    if r() < 0.62:
        p.append(GURULTU[int(r() * 8)])
    if r() < 0.30:
        p.append(BOLGE[int(r() * 5)])
    return {"metin": ", ".join(p), "tur": t, "supheli": 1 if r() < SUP_P[t] else 0}


NOT = [not_kur(i) for i in range(1600)]
EGT, SIN = NOT[:1100], NOT[1100:]
TUR_I = {t: i for i, t in enumerate(TUR)}
say = {}
for x in EGT:
    say[x["tur"]] = say.get(x["tur"], 0) + 1
EN_SIK = max(say, key=say.get)
TABAN = sum(x["tur"] == EN_SIK for x in SIN) / len(SIN)
for i in (3, 25, 40):
    print(f"not: {NOT[i]['metin']}  ->  {NOT[i]['tur']}")
print(f"egitim {len(EGT)}, ayrilmis {len(SIN)}, ortalama belirtec "
      f"{sum(len(x['metin'].split()) for x in NOT) / len(NOT):.2f}")
print("ayrilmis kumede " + ", ".join(
    f"{t} {sum(x['tur'] == t for x in SIN) / len(SIN):.4f}" for t in TUR))
print(f"en sik sinif '{EN_SIK}', alanin tabani {TABAN:.4f}")
```

```
not: baglanti degistirilmis, kelepce gevsek, dogu hatti  ->  kacak suphesi
not: bodrum katina inilemedi, abone evde degildi, sayac cami kirik, bahce icinde  ->  erisilemedi
not: vanada sorun yok, gostergede rakam net, sayac durmus, kuzey hatti  ->  olagan
egitim 1100, ayrilmis 500, ortalama belirtec 6.68
ayrilmis kumede olagan 0.4420, erisilemedi 0.2340, sayac arizasi 0.1920, kacak suphesi 0.1320
en sik sinif 'olagan', alanin tabani 0.4420
```

İkinci ve üçüncü örnek notlar kurgunun neyi zorlaştırdığını gösteriyor. İkincisi "erisilemedi"
türünden üretilmiş ama içinde bir arıza kaydı taşıyor; üçüncüsü "olagan" türünden üretilmiş ama
"sayac durmus" ifadesi arıza öbeğinden geliyor. Metin etiketi tam belirlemez, yalnız işaret eder.

Alanın tabanı 0,4420. Bu sayı hiçbir sözcüğe bakmadan her nota "olağan" yazan bir yordamın
ayrılmış kümedeki oranıdır ve bundan sonraki her sayı ona karşı okunur.

## Üç Adım, On İki Kurulum

Boru hattı üç kararın çarpımıdır. Belirteçleme üç seçenektir: **kaba** (yalnız boşluktan bölme,
noktalama sözcüğe yapışık kalır), **özenli** (virgül kırpılır, küçük harfe indirgenir), **kırpık**
(özenlinin üstüne her sözcük ilk beş karaktere indirgenir — eklemeli bir dilde gövdelemenin en kaba
yaklaşımı). Ağırlıklandırma iki seçenektir: ham **sıklık**, ya da sıklığın **ters belge
sıklığıyla** çarpımı. Sınıflandırıcı iki seçenektir. Üç kararın on iki bileşimi vardır
ve on ikisi de aynı ayrılmış kümede ölçülür.

```python
# Boru hattinin uc adimi. Her adim YALNIZ egitim kumesinden ogrenilir.
BOL = {"kaba": lambda m: m.split(),
       "ozenli": lambda m: [w.strip(",").lower() for w in m.split() if w.strip(",")],
       "kirpik": lambda m: [w.strip(",").lower()[:5] for w in m.split() if w.strip(",")]}


def sozluk_kur(D, bol):
    d = {}
    for x in D:
        for w in set(bol(x["metin"])):
            d[w] = d.get(w, 0) + 1
    kelime = sorted(w for w, c in d.items() if c >= 2)
    return ({w: i for i, w in enumerate(kelime)},
            {i: math.log(len(D) / d[w]) for i, w in enumerate(kelime)})


def vektor(m, bol, S, TBS=None):
    v = {}
    for w in bol(m):
        if w in S:
            v[S[w]] = v.get(S[w], 0.0) + 1.0
    if TBS:
        for i in v:
            v[i] *= TBS[i]
    n = math.sqrt(sum(u * u for u in v.values())) or 1.0
    return {i: u / n for i, u in v.items()}


def sinif_ortalamasi(D, V):                 # MODELDIR: her sinifin ortalama vektoru
    C = [{} for _ in TUR]
    for x, v in zip(D, V):
        c = C[TUR_I[x["tur"]]]
        for i, u in v.items():
            c[i] = c.get(i, 0.0) + u
    for c in C:
        n = math.sqrt(sum(u * u for u in c.values())) or 1.0
        for i in c:
            c[i] /= n
    return lambda v: max(range(4), key=lambda j: sum(u * C[j].get(i, 0.0)
                                                     for i, u in v.items()))


def dogrusal_model(D, V, boy, tur=150, adim=3.0):   # MODELDIR: dort sinifli dogrusal
    W, b = [[0.0] * boy for _ in TUR], [0.0] * 4
    y, n = [TUR_I[x["tur"]] for x in D], len(D)
    for _ in range(tur):
        gW, gb = [{} for _ in TUR], [0.0] * 4
        for v, t in zip(V, y):
            o = [sum(W[j][i] * u for i, u in v.items()) + b[j] for j in range(4)]
            e = [math.exp(z - max(o)) for z in o]
            s = sum(e)
            for j in range(4):
                d = e[j] / s - (1.0 if j == t else 0.0)
                gb[j] += d
                for i, u in v.items():
                    gW[j][i] = gW[j].get(i, 0.0) + d * u
        for j in range(4):
            b[j] -= adim * gb[j] / n
            for i, g in gW[j].items():
                W[j][i] -= adim * g / n
    return lambda v: max(range(4), key=lambda j: sum(W[j][i] * u
                                                     for i, u in v.items()) + b[j])


def olc(kes, D, V):
    return sum(kes(v) == TUR_I[x["tur"]] for x, v in zip(D, V)) / len(D)


ANAHTAR = ("muhur", "erisim", "sayac", "gosterge", "kelepce")


def elle(m):                                # M27/K02'nin elle sayilmis metin olculeri
    w = BOL["ozenli"](m)
    v = {0: len(m) / 60.0, 1: len(w) / 10.0}
    for j, a in enumerate(ANAHTAR):
        v[2 + j] = 1.0 if any(a in u for u in w) else 0.0
    n = math.sqrt(sum(u * u for u in v.values())) or 1.0
    return {i: u / n for i, u in v.items()}


VE, VS = [elle(x["metin"]) for x in EGT], [elle(x["metin"]) for x in SIN]
ELLE = olc(dogrusal_model(EGT, VE, 7), SIN, VS)
IZGARA = {}
print(f"{'belirtecleme':<13}{'sozluk':>7}{'agirlik':>11}{'sinif ort.':>12}{'dogrusal':>10}")
for ad, bol in BOL.items():
    S, TBS = sozluk_kur(EGT, bol)
    for ag, t in (("sayim", None), ("agirlikli", TBS)):
        VE = [vektor(x["metin"], bol, S, t) for x in EGT]
        VS = [vektor(x["metin"], bol, S, t) for x in SIN]
        a = olc(sinif_ortalamasi(EGT, VE), SIN, VS)
        d = olc(dogrusal_model(EGT, VE, len(S)), SIN, VS)
        IZGARA[(ad, ag)] = (a, d)
        print(f"{ad if ag == 'sayim' else '':<13}{len(S) if ag == 'sayim' else '':>7}"
              f"{ag:>11}{a:>12.4f}{d:>10.4f}")
print(f"taban {TABAN:.4f}; elle sayilmis yedi olcu + dogrusal model {ELLE:.4f}")
```

```
belirtecleme  sozluk    agirlik  sinif ort.  dogrusal
kaba             156      sayim      0.9040    0.9500
                      agirlikli      0.9300    0.9580
ozenli           109      sayim      0.8940    0.9620
                      agirlikli      0.9200    0.9580
kirpik            89      sayim      0.8700    0.9500
                      agirlikli      0.9040    0.9440
taban 0.4420; elle sayilmis yedi olcu + dogrusal model 0.5500
```

Son satır bu kursun taban okumasının ikinci basamağıdır. M27/K02 `oznitelik-secimi/02` bir saha
notundan elle beş sayı çıkarmış ve bunların ayrılmış kümeye 0,0317 kattığını ölçmüştü; orada görev
ikili şüphe kestirimiydi. Aynı yaklaşım burada dört sınıflı olay türü görevine uygulandığında
0,5500 veriyor — tabanın 0,1080 üstünde. Sözcük torbasının aynı ayrılmış kümede verdiği en düşük
sayı 0,8700, en yükseği 0,9620.

## Bir Adımın Katkısı Tek Sayı Değildir

On iki kurulum, "hangi adım kaç puan katıyor" sorusunu tek bir çıkarma işlemiyle cevaplamayı
imkânsız kılar. Her adımın katkısı, ötekilerin hangi değerde durduğuna bağlıdır ve bu bağımlılık
sayılabilir: bir adım değiştirilirken geri kalan bütün kurulumlar sabit tutulur ve fark her birinde
ayrı ayrı okunur.

```python
# Bir adimin katkisi tek sayi degildir: oteki adimlarin her kurulumunda ayri olculur.
ADIM = [("belirtecleme kaba -> ozenli",
         [IZGARA[("ozenli", g)][k] - IZGARA[("kaba", g)][k]
          for g in ("sayim", "agirlikli") for k in (0, 1)]),
        ("belirtecleme ozenli -> kirpik",
         [IZGARA[("kirpik", g)][k] - IZGARA[("ozenli", g)][k]
          for g in ("sayim", "agirlikli") for k in (0, 1)]),
        ("agirliklandirma sayim -> agirlikli",
         [IZGARA[(b, "agirlikli")][k] - IZGARA[(b, "sayim")][k]
          for b in BOL for k in (0, 1)]),
        ("siniflandirici ortalama -> dogrusal",
         [IZGARA[(b, g)][1] - IZGARA[(b, g)][0]
          for b in BOL for g in ("sayim", "agirlikli")]),
        ("temsil elle sayim -> sozcuk torbasi",
         [IZGARA[(b, g)][k] - ELLE for b in BOL
          for g in ("sayim", "agirlikli") for k in (0, 1)])]
print(f"{'adim':<38}{'olcum':>6}{'en dusuk':>10}{'en yuksek':>11}{'ortalama':>10}")
for ad, f in ADIM:
    print(f"{ad:<38}{len(f):>6}{min(f):>+10.4f}{max(f):>+11.4f}"
          f"{sum(f) / len(f):>+10.4f}")

S, _ = sozluk_kur(EGT, BOL["ozenli"])
disi = [sum(w not in S for w in BOL["ozenli"](x["metin"])) for x in SIN]
toplam = sum(len(BOL["ozenli"](x["metin"])) for x in SIN)
print(f"sozluk yalniz egitimden kuruldu: {len(S)} sozcuk; ayrilmis kumede "
      f"sozluk disi belirtec {sum(disi)}/{toplam}")
en_iyi = max(IZGARA.items(), key=lambda kv: kv[1][1])
print(f"en yuksek kurulum {en_iyi[0][0]} + {en_iyi[0][1]} + dogrusal "
      f"{en_iyi[1][1]:.4f}; tabanin {en_iyi[1][1] - TABAN:+.4f} uzerinde")
```

```
adim                                   olcum  en dusuk  en yuksek  ortalama
belirtecleme kaba -> ozenli                4   -0.0100    +0.0120   -0.0020
belirtecleme ozenli -> kirpik              4   -0.0240    -0.0120   -0.0165
agirliklandirma sayim -> agirlikli         6   -0.0060    +0.0340   +0.0140
siniflandirici ortalama -> dogrusal        6   +0.0280    +0.0800   +0.0500
temsil elle sayim -> sozcuk torbasi       12   +0.3200    +0.4120   +0.3787
sozluk yalniz egitimden kuruldu: 109 sozcuk; ayrilmis kumede sozluk disi belirtec 0/3305
en yuksek kurulum ozenli + sayim + dogrusal 0.9620; tabanin +0.5200 uzerinde
```

Tablonun en büyük satırı en alttadır ve bu dersin asıl cevabıdır: farkın neredeyse tamamı
**temsilden** gelir. Elle sayılmış yedi ölçüyü sözcük torbasıyla değiştirmek on iki kurulumun
hepsinde en az 0,3200 katıyor. Sınıflandırıcıyı değiştirmek ortalama 0,0500, ağırlıklandırma 0,0140
katıyor. Yedi sayı ile yüz dokuz sayı arasındaki fark, sınıf ortalaması ile doğrusal model
arasındaki farkın yedi katıdır.

Ağırlıklandırma satırı işaret değiştiriyor ve bu dersin ikinci bulgusudur. Sınıf ortalamasıyla
çalışıldığında ters belge sıklığı üç belirteçlemede de artı katkı veriyor, en yükseği 0,0340;
doğrusal modelle çalışıldığında iki kurulumda eksiye iniyor. Nedeni yordamların yapısındadır:
sınıf ortalaması bütün sözcüklere eşit güvenir, bu yüzden yüksek sıklıklı taşıyıcı sözcüklerin
bastırılması ona yarar. Doğrusal model o bastırmayı ağırlıklarıyla zaten öğrenmektedir ve dışarıdan
gelen ikinci bir bastırma bilgi eklemez. "Terim ağırlıklandırma kaç puan katar" sorusunun tek bir
cevabı yoktur; sınıflandırıcı yazılmadan sorulmuş bir sorudur.

Belirteçleme satırlarının ikisi de eksidedir. Kaba bölmeden özenliye geçiş sözlüğü 156'dan 109'a
indiriyor ve ortalamada 0,0020 kaybettiriyor; ek kırpma sözlüğü 89'a indirirken 0,0165
kaybettiriyor. Kırpma "sayac", "sayaci", "sayacin" biçimlerini tek bir belirteçte topluyor — ama
"kapak temiz" ile "kapakta iz yok" ayrımını da siliyor, çünkü ikisinin ayırt edici sözcükleri beş
karakterde kesişiyor. Sözlüğü küçültmek bir maliyet ölçüsüdür, başarım ölçüsü değildir; ikisinin
aynı yöne gitmesi gerekmez.

Son iki satır boru hattı kuralının bu kümedeki bedelini gösterir. Sözlük yalnız eğitim kümesinden
kurulduğu için ayrılmış kümedeki bazı sözcüklerin dışarıda kalması beklenirdi; burada sözlük dışı
belirteç sayısı 3.305'te sıfırdır, çünkü kurgunun sözlüğü kapalıdır ve 1.100 not bütün ifadeleri
görmeye yeter. Kuralın burada bedeli yoktur, ama kural yine de uygulanmıştır: bedelin sıfır olduğu
ancak ölçüldükten sonra bilinir.

## Özet

- Belge düzeyinde sınıflandırmada karar birimi belgedir; girdinin belirteç sayısı değişkendir,
  çıktı tek bir etikettir.
- Alanın tabanı en sık sınıftır ve 0,4420 verir; elle sayılmış yedi metin ölçüsü 0,5500, sözcük
  torbası ile doğrusal model 0,9620 veriyor.
- Farkın neredeyse tamamı temsilden gelir: elle sayımdan sözcük torbasına geçiş on iki kurulumun
  hepsinde en az 0,3200 katıyor, sınıflandırıcı adımı ortalama 0,0500 katıyor.
- Bir adımın katkısı tek sayı değildir: terim ağırlıklandırma sınıf ortalamasıyla 0,0340'a çıkar,
  doğrusal modelle 0,0060 eksiye iner.
- Sözlüğü küçültmek başarımı artırmaz: ek kırpma sözlüğü 109'dan 89'a indirirken ortalama 0,0165
  kaybettirir.

## Sonraki Adım

Bu derste sözcük torbası tabanı 0,5200 geçti, ama bunun için 1.100 etiketli not harcandı. Her not
bir saha ziyaretinin karşılığıdır ve elde yüz tane olabilir. Etiketsiz not ise boldur: ölçüm ağı
her dönem binlerce not üretir ve hiçbirine olay türü yazılmamıştır. Bu notlardan bir
**vekil görev** kurulabilir — bir sözcük gizlenip komşularından kestirilir — ve orada
öğrenilen temsil etiketli göreve taşınabilir. Sonraki ders bu döngüyü ölçer: maskeli
kestirimle önceden eğitilen bir gömme, etiketli örnek sayısı azaldıkça sıfırdan eğitilen
kurulumu ne kadar geçiyor ve fark hangi örnek sayısında kapanıyor.
