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:
Bir sorgu sabitken 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ı 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.