İçeriğe geç
academia.sh

Ders 03 / 16

Benzerlik Ölçütleri

Aynı vektörlerin iki ayrı ölçütle sıralanması ve seçimin getirilen parçayı ne kadar değiştirdiği. İç çarpım, açı benzerliğinin iki vektörün boyuyla çarpımıdır; bir sorgu için sorgu boyu sabit olduğundan bütün sıra farkı belge vektörünün boyundan gelir ve bu boy en kısa çeyrekte 4,6864, en uzun çeyrekte 5,3966'dır. Kırk sorgunun otuzunda ilk üç sonuç ayrışıyor; açı benzerliği 0,4600 erişim kesinliği ve 0,5000 kavram isabeti verirken iç çarpım 0,3900 ve 0,4250'de kalıyor ve ikinci bir gömme modelinde de aynı yön çıkıyor. Uzunluk yanlılığı iç çarpımdadır: getirilen kümenin ortalaması 64,3 belirteç, açı benzerliğinde 54,6, dağarcıkta 61,5; ilgili belgelerin ortalaması da 61,5 olduğuna göre uzunluk ilgililik taşımıyor.

İçindekiler

Önceki iki ders benzerliği hep aynı yordamla hesapladı: vektörler birim uzunluğa getirildi, sonra karşılıklı koordinatlar çarpılıp toplandı. Birinci adım sessiz bir karardı ve hiç tartışılmadı. Vektörler birim uzunluğa getirilmezse aynı çarpım başka bir sayı verir ve başka bir sıralama üretir.

İki ölçüt bu iki durumun adıdır. Açı benzerliği iki vektör arasındaki açıyı ölçer ve uzunluklarını yok sayar. İç çarpım koordinat çarpımlarını doğrudan toplar ve uzunluğu içinde taşır. Aralarındaki bağıntı tek satırdır:

ic¸ c¸arpım(u,v)=ac¸ı benzerlig˘i(u,v)uv\text{iç çarpım}(u, v) = \text{açı benzerliği}(u, v) \cdot \lVert u \rVert \cdot \lVert v \rVert

Bir sorgu sabitken u\lVert u \rVert bütün belgeler için aynıdır. Buradan çıkan sonuç bu dersin ekseni: iki ölçüt arasındaki bütün sıra farkı v\lVert v \rVert değerinden, yani belge vektörünün boyundan gelir.

  • GM18. Kod benzeticidir, dağarcık ve gömme yordamı kurgudur, tohum 20260218. Boyut otuz iki, getirilen parça beş, ilgili belge tanımı önceki iki dersle aynı, gömme alan içi.
  • GM19. Tek vektör kümesi, iki ölçüt. Paylaşılan gömme yordamı vektörü birim uzunluğa getirir, ham yordam getirmez; açı benzerliği birim vektörlerin iç çarpımıdır.
  • GM20. Yukarıdaki bağıntı blokta sayıyla denetlenir.
  • GM21. Belge uzunluğu belirteç sayısıyla ölçülür; dağarcıkta otuz iki ile doksan altı arası değişiyor.
  • GM22. Ayrışma ilk üç sonucun kümesi üzerinden sayılır: iki ölçüt aynı üç belgeyi getiriyorsa sıraları farklı olsa bile ayrışmamış sayılır.
  • GM23. Uzunluk yanlılığı iki tabana karşı okunur: getirilen kümenin ortalama belirteci dağarcık ortalamasına, ilk beşte en uzun çeyreğin payı o çeyreğin dağarcıktaki payına karşı.
  • GM24. Koşumdan bağımsız ölçü aynı aileden ikinci bir gömme modelidir (izdüşüm tohumu 20260219). Sıralama iki modelde aynı yönde çıkmazsa ölçülmüş sayılmaz.

Tek Vektör Kümesi, İki Ölçüt

İlk blok dağarcığı kurar, normalleştirilmemiş vektörü üreten yordamı ekler ve iki şeyi gösterir: belge vektörünün boyu uzunlukla nasıl büyüyor, ve bağıntı tutuyor mu.

# BENZETICI -- KURGUDUR. Gercek bir gomme uc noktasi cagrilmaz. Dagarcik,
# kavram ekseni, gomme yordami ve sorgu kumesi KURGUDUR; hicbir gercek
# kurum, urun ya da belge degildir.
TOHUM, M32 = 20260218, 0xFFFFFFFF
BOYUT = 32


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 ayrik(u, w):
    t = 0.0
    for i, x in enumerate(w):
        t += x
        if u < t:
            return i
    return len(w) - 1


def belirtecle(m):
    b = []
    for s in m.lower().replace(",", " , ").split():
        while len(s) > 5:
            b.append(s[:5])
            s = s[5:]
        b.append(s)
    return b


# ---- KURGU anlam ekseni: her kavramin belge dilinde ve sorgu dilinde ayri yuzeyi var
SINIF = ["tarife", "ariza", "sayac", "kesinti", "bakim"]
KOD = {"tarife": "TR", "ariza": "AR", "sayac": "SY", "kesinti": "KS", "bakim": "BK"}
KAVRAM = {                       # kavram: (sinif, belge yuzeyi, sorgu yuzeyi)
    "basamak":   ("tarife", "kademe esigi", "hangi dilimdeyim"),
    "birim":     ("tarife", "birim ucret", "metrekup fiyati"),
    "abonetip":  ("tarife", "abone tipi", "mesken mi isyeri mi"),
    "gecis":     ("tarife", "tarife gecisi", "plan degistirme"),
    "arizakod":  ("ariza", "ariza kodu", "hata numarasi"),
    "sizinti":   ("ariza", "hat sizintisi", "su kacagi"),
    "basinc":    ("ariza", "basinc dususu", "zayif akis"),
    "ekip":      ("ariza", "saha ekibi", "gorevli ne zaman gelir"),
    "endeks":    ("sayac", "endeks degeri", "sayac ustundeki rakam"),
    "okuma":     ("sayac", "okuma yordami", "nasil kaydediliyor"),
    "degisim":   ("sayac", "sayac degisimi", "cihaz yenileme"),
    "dogrula":   ("sayac", "okuma dogrulamasi", "yanlis girilmis mi"),
    "planli":    ("kesinti", "planli kesinti", "onceden duyurulan durma"),
    "duyuru":    ("kesinti", "duyuru kanali", "nereden ogrenirim"),
    "sure":      ("kesinti", "kesinti suresi", "ne kadar surer"),
    "geridonus": ("kesinti", "yeniden verme", "ne zaman gelir"),
    "periyot":   ("bakim", "periyodik bakim", "duzenli kontrol"),
    "vana":      ("bakim", "vana kontrolu", "musluk kapatma duzeni"),
    "filtre":    ("bakim", "filtre degisimi", "temizleme parcasi"),
    "kalib":     ("bakim", "kalibrasyon kaydi", "olcum ayari"),
}
ANAHTAR = list(KAVRAM)
ORTAK = ["kayit", "bolge", "donem", "islem", "form", "onay", "not"]

# ---- KURGU dagarcik
BELGE = []
for i in range(200):
    r = uretec(TOHUM + 7919 * i)
    s = SINIF[ayrik(r(), [0.22, 0.24, 0.20, 0.18, 0.16])]
    kav = [k for k in ANAHTAR if KAVRAM[k][0] == s]
    ana = kav[int(r() * len(kav))]
    n = 2 + int(r() * 4)
    par, kavlar = [], [ana]
    for _ in range(n):
        y = kav[int(r() * len(kav))]
        kavlar.append(y)
        o = ORTAK[int(r() * len(ORTAK))]
        par.append(f"{KAVRAM[y][1]} icin {o} tutulur ve {KAVRAM[ana][1]} ile birlikte yazilir")
    BELGE.append({"kod": f"{KOD[s]}{i + 1:03d}", "sinif": s, "ana": ana, "kavram": kavlar,
                  "baslik": f"{KAVRAM[ana][1]} yordami", "par": par})


def metin(d):
    return d["baslik"] + " " + " ".join(d["par"])


# ---- KURGU gomme: yuzey once kavrama, kavram sonra boyuta dusuruluyor
def _kavramla(m, alan=True):
    v = [0.0] * len(ANAHTAR)
    dm = " " + m.lower() + " "
    for i, k in enumerate(ANAHTAR):
        bel, sor = KAVRAM[k][1], KAVRAM[k][2]
        if bel in dm:
            v[i] += 1.0
        if sor in dm:
            v[i] += 1.0 if alan else 0.0      # alan disi gomme sorgu dilini tanimaz
    if not alan:
        for o in ORTAK:
            if " " + o + " " in dm:
                for i in range(len(ANAHTAR)):
                    v[i] += 0.05
    return v


IZDUS = []
for i in range(len(ANAHTAR)):
    r = uretec(TOHUM ^ (i + 1) * 2654435761)
    IZDUS.append([r() * 2 - 1 for _ in range(64)])


def gom(m, boyut=BOYUT, alan=True):
    k = _kavramla(m, alan)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS[i][j % 64]
    n = sum(x * x for x in v) ** 0.5
    return [x / n for x in v] if n else v


def aci(a, b):
    return sum(x * y for x, y in zip(a, b))


# ---- KURGU sorgu kumesi: sorgu dili belge dilinden ayri
SORGU = []
for i in range(40):
    r = uretec(TOHUM + 104729 * i)
    d = BELGE[int(r() * len(BELGE))]
    SORGU.append({"metin": f"{KAVRAM[d['ana']][2]} {ORTAK[int(r() * len(ORTAK))]}",
                  "sinif": d["sinif"], "kavram": d["ana"]})

# Iki olcut, tek vektor kumesi: paylasilan gom() vektoru birim uzunluga getirir,
# ham() getirmez. Aci benzerligi birim vektorlerin ic carpimidir.
def ham(m, boyut=BOYUT, alan=True):
    k = _kavramla(m, alan)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS[i][j % 64]
    return v


def uzunluk(v):
    return sum(x * x for x in v) ** 0.5


BELIRTEC = [len(belirtecle(metin(d))) for d in BELGE]
NORM = [uzunluk(ham(metin(d))) for d in BELGE]
sirali = sorted(range(len(BELGE)), key=lambda i: BELIRTEC[i])
c = len(BELGE) // 4
kisa, uz = sirali[:c], sirali[-c:]
print(f"dagarcik: belirtec ortalamasi {sum(BELIRTEC) / len(BELGE):.1f} ,"
      f" en kisa {BELIRTEC[sirali[0]]} , en uzun {BELIRTEC[sirali[-1]]}")
print(f"  en kisa ceyrek : ortalama {sum(BELIRTEC[i] for i in kisa) / c:.1f} belirtec ,"
      f" ham vektor uzunlugu {sum(NORM[i] for i in kisa) / c:.4f}")
print(f"  en uzun ceyrek : ortalama {sum(BELIRTEC[i] for i in uz) / c:.1f} belirtec ,"
      f" ham vektor uzunlugu {sum(NORM[i] for i in uz) / c:.4f}")
q, d = SORGU[0], BELGE[0]
qh, bh = ham(q["metin"]), ham(metin(d))
print(f"\nozdeslik denetimi , sorgu 1 ile {d['kod']}:")
print(f"  ic carpim                  {aci(qh, bh):.6f}")
print(f"  aci benzerligi             {aci(gom(q['metin']), gom(metin(d))):.6f}")
print(f"  aci * iki vektorun boyu    "
      f"{aci(gom(q['metin']), gom(metin(d))) * uzunluk(qh) * uzunluk(bh):.6f}")
dagarcik: belirtec ortalamasi 61.5 , en kisa 32 , en uzun 96
  en kisa ceyrek : ortalama 37.7 belirtec , ham vektor uzunlugu 4.6864
  en uzun ceyrek : ortalama 85.8 belirtec , ham vektor uzunlugu 5.3966

ozdeslik denetimi , sorgu 1 ile BK001:
  ic carpim                  -0.218248
  aci benzerligi             -0.011168
  aci * iki vektorun boyu    -0.218248

Çeyrek satırları mekanizmayı veriyor. En kısa çeyrekte belge ortalama 37,7 belirteç ve ham vektör boyu 4,6864; en uzun çeyrekte 85,8 belirteç ve 5,3966. Belge iki buçuk katına çıkarken boy yalnız yüzde on beş büyüyor, ama iç çarpım o boyla çarpıldığı için bu yüzde on beş doğrudan puana giriyor. Nedeni yordamda yazılı: bir belge ne kadar çok kavram anıyorsa kavram vektörüne o kadar çok ağırlık düşüyor.

Özdeşlik denetimi bağıntının tuttuğunu gösteriyor: iç çarpım doğrudan hesaplandığında ve açı benzerliği iki boyla çarpıldığında altı basamağa kadar aynı sayı çıkıyor. İki ölçüt ayrı yordamlar değil; biri öbürünün boylarla çarpılmış hâlidir.

Ölçüt Değişince Sıra Ne Kadar Değişiyor

Aşağıdaki blok aynı kırk sorguyu iki ölçütle koşturur ve bunu iki gömme modelinde tekrarlar. Her model için önce ilk üç sonucu ayrışan sorgu sayısı, sonra dört erişim ölçüsü ve getirilen kümenin ortalama belirteci basılır.

K = 5
ILGILI = {k: sum(1 for d in BELGE if d["ana"] == k) for k in ANAHTAR}

# Ayni aileden ikinci gomme modeli: yalniz izdusum tohumu farkli (20260219).
IZDUS2 = []
for i in range(len(ANAHTAR)):
    r = uretec((TOHUM + 1) ^ (i + 1) * 2654435761)
    IZDUS2.append([r() * 2 - 1 for _ in range(64)])


def ham2(m, boyut=BOYUT):
    k = _kavramla(m)
    v = [0.0] * boyut
    for i, a in enumerate(k):
        if a:
            for j in range(boyut):
                v[j] += a * IZDUS2[i][j % 64]
    return v


def birim(v):
    n = uzunluk(v)
    return [x / n for x in v] if n else v


def diz(qv, vek):
    return sorted(range(len(BELGE)), key=lambda i: (-aci(qv, vek[i]), i))


def olc(gomucu):
    hv = [gomucu(metin(d)) for d in BELGE]
    av = [birim(v) for v in hv]
    sayi = {"aci": [0.0] * 5, "ic carpim": [0.0] * 5}
    ayrisan = 0
    for q in SORGU:
        qh = gomucu(q["metin"])
        a, b = diz(birim(qh), av), diz(qh, hv)
        ayrisan += set(a[:3]) != set(b[:3])
        for ad, ust in (("aci", a[:K]), ("ic carpim", b[:K])):
            t = sum(BELGE[i]["ana"] == q["kavram"] for i in ust)
            s = sayi[ad]
            s[0] += t / K
            s[1] += t / ILGILI[q["kavram"]]
            s[2] += BELGE[ust[0]]["ana"] == q["kavram"]
            s[3] += BELGE[ust[0]]["sinif"] == q["sinif"]
            s[4] += sum(BELIRTEC[i] for i in ust) / K
    n = len(SORGU)
    return ayrisan, {ad: [x / n for x in s] for ad, s in sayi.items()}


for etiket, gomucu in (("model 1", ham), ("model 2", ham2)):
    ayrisan, sonuc = olc(gomucu)
    print(f"{etiket} : ilk uc sonucu ayrisan sorgu {ayrisan}/{len(SORGU)}")
    print("  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec")
    for ad, s in sonuc.items():
        print(f"  {ad:<10} " + " ".join(f"{x:7.4f}" for x in s[:4]) + f" {s[4]:15.1f}")
model 1 : ilk uc sonucu ayrisan sorgu 30/40
  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec
  aci         0.4600  0.2223  0.5000  1.0000            54.6
  ic carpim   0.3900  0.1879  0.4250  0.9500            64.3
model 2 : ilk uc sonucu ayrisan sorgu 27/40
  olcut      kesinlik    anma  kavram   sinif  ortalama belirtec
  aci         0.4050  0.2035  0.5250  1.0000            52.6
  ic carpim   0.3400  0.1680  0.3500  0.9500            57.9

İlk satır ölçüt seçiminin bir ayrıntı olmadığını söylüyor: kırk sorgunun otuzunda iki ölçüt farklı bir ilk üçlü getiriyor. Aynı vektörler, aynı dağarcık, aynı sorgular; değişen tek şey puanın normalleştirilmiş vektörlerden mi ham vektörlerden mi okunduğu.

Dört ölçüde açı benzerliği her sütunda önde: kesinlik 0,4600’e karşı 0,3900, anma 0,2223’e karşı 0,1879, kavram isabeti 0,5000’e karşı 0,4250, sınıf isabeti 1,0000’e karşı 0,9500. İkinci gömme modelinde sayılar değişiyor ama yön değişmiyor: 0,4050’ye karşı 0,3400 ve 0,5250’ye karşı 0,3500. Ölçüt sıralaması tek bir izdüşümün çekilişi değil.

Son sütun farkın nereden geldiğini gösteriyor. Açı benzerliğinin getirdiği beş belgenin ortalaması 54,6 belirteç, iç çarpımınki 64,3. Aradaki 9,7 belirteçlik kayma bir yan ürün değil, ölçütün tanımının doğrudan sonucudur.

Uzunluğun İlgililik Taşımadığı Yerde Uzunluğa Bakmak

Bir kaymanın yanlılık sayılabilmesi için uzunluğun ilgililik taşımadığının gösterilmesi gerekir. Aşağıdaki blok iki tabanı basar: dağarcığın ortalama uzunluğu ile ilgili belgelerin ortalama uzunluğu, ve en uzun çeyreğin iki ölçütün ilk beşindeki payı.

c = len(BELGE) // 4
enuzun = set(sorted(range(len(BELGE)), key=lambda i: -BELIRTEC[i])[:c])
ilg = {k: [i for i, d in enumerate(BELGE) if d["ana"] == k] for k in ANAHTAR}
print(f"dagarcik ortalamasi {sum(BELIRTEC) / len(BELGE):.1f} belirtec ,"
      f" en uzun ceyregin payi {c / len(BELGE):.4f}")
print("ilgili belgelerin ortalamasi %.1f belirtec"
      % (sum(sum(BELIRTEC[i] for i in ilg[q["kavram"]]) / len(ilg[q["kavram"]])
             for q in SORGU) / len(SORGU)))
hv = [ham(metin(d)) for d in BELGE]
av = [birim(v) for v in hv]
print("\nolcut      ilk beste en uzun ceyregin payi")
for ad, vek, qf in (("aci", av, lambda q: birim(ham(q["metin"]))),
                    ("ic carpim", hv, lambda q: ham(q["metin"]))):
    p = sum(sum(1 for i in diz(qf(q), vek)[:K] if i in enuzun) / K
            for q in SORGU) / len(SORGU)
    print(f"{ad:<10} {p:32.4f}")
dagarcik ortalamasi 61.5 belirtec , en uzun ceyregin payi 0.2500
ilgili belgelerin ortalamasi 61.5 belirtec

olcut      ilk beste en uzun ceyregin payi
aci                                  0.0800
ic carpim                            0.2500

İlk iki satır kararı veriyor. Dağarcığın ortalaması 61,5 belirteç; ilgili belgelerin ortalaması da 61,5. Uzunluk ile ilgililik arasında bu dağarcıkta bir bağ yok, yani uzun bir belgenin sorguya yanıt verme şansı kısa bir belgeden fazla değil.

Alt tablo bunun sıralamaya nasıl yansıdığını yazıyor. En uzun çeyrek dağarcığın 0,2500’ünü oluşturuyor. İç çarpımın ilk beşinde bu çeyreğin payı 0,2500, yani taban oranın tam kendisi; açı benzerliğinin ilk beşinde 0,0800, yani taban oranın üçte birinden az. İki ölçüt uzunluğa karşı iki ayrı yerde duruyor: iç çarpım uzun belgeleri dağarcıktaki paylarında tutuyor, açı benzerliği onları eliyor.

Elemenin niçin işe yaradığı boyun tanımından okunur. Uzun belge daha çok kavram anıyor; ham vektörü daha uzun ama daha dağınık. Açı benzerliği boyu bölerek attığı için kalan soru “kaç kavram anılmış” değil, “hangi kavrama ne oranda yer verilmiş” oluyor; sorgu tek bir kavramı hedeflediğine göre kazanan yoğunlaşmış belge oluyor.

Buradan çıkan sonuç ölçüt adlarından bağımsızdır. Bütün vektörler birim uzunluktaysa iki ölçüt aynı sıralamayı verir; boylar bire eşit olduğunda çarpım hiçbir şeyi değiştirmez. Asıl karar “hangi ölçüt” değil, vektörler saklanırken normalleştiriliyor mu kararıdır. Normalleştirme yapılıyorsa iç çarpım bir bölme işleminden tasarruf eder ve sonuç aynıdır; yapılmıyorsa ölçüt seçimi kırk sorgunun otuzunda getirilen parçayı değiştirir.

Özet

  • İç çarpım, açı benzerliğinin iki vektörün boyuyla çarpımıdır; sabit bir sorguda bütün sıra farkı belge vektörünün boyundan gelir.
  • Belge vektörünün boyu uzunlukla büyür: en kısa çeyrekte 4,6864, en uzun çeyrekte 5,3966.
  • Kırk sorgunun otuzunda iki ölçüt farklı bir ilk üçlü getiriyor.
  • Açı benzerliği dört ölçüde de önde (0,4600 / 0,2223 / 0,5000 / 1,0000 karşısında 0,3900 / 0,1879 / 0,4250 / 0,9500) ve ikinci gömme modelinde yön aynı kalıyor.
  • Uzunluk yanlılığı iç çarpımdadır: getirilen kümenin ortalaması 64,3 belirteç, açı benzerliğinde 54,6, dağarcıkta 61,5; en uzun çeyreğin ilk beşteki payı 0,2500 ile 0,0800.
  • İlgili belgelerin ortalaması da 61,5 belirteçtir, yani uzunluk ilgililik taşımaz; vektörler birim uzunlukta saklanıyorsa iki ölçüt aynı sıralamayı verir.

Sonraki Adım

Üç derste erişimin üç kararı ölçüldü: sözcük mü anlam mı, hangi gömme modeli, hangi ölçüt. Üçünde de ortak kalan ve hiç sorulmayan bir şey vardı: her sorgu bütün dağarcıkla karşılaştırıldı, kırk sorgu ve iki yüz belge için 8000 karşılaştırma yapıldı, tam sıralama her seferinde baştan kuruldu. İki yüz belgede bu bir sorun değil; dağarcık yüz binlerce parçaya çıktığında her sorgu için bütün vektörlere dokunmak sürdürülemez. Sonraki ders vektörleri bir dizin içine koyar ve tam taramayı taban alarak sorar: bütün belgelere dokunmadan getirilen küme dokunularak getirilenden ne kadar sapıyor ve karşılaştırma sayısı karşılığında hangi anma veriliyor.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat