---
title: 'Dizey Ayrıştırma'
source: 'https://academia.sh/tr/kurslar/pekistirmeli-ve-oneri/dizey-ayristirma'
course: 'Pekiştirmeli Öğrenme ve Öneri Sistemleri'
language: tr
updated: '2026-08-17T18:10:16+00:00'
license: 'CC BY-SA 4.0'
---

# Dizey Ayrıştırma

Eksik girdili bir etkileşim dizeyinde gözlenmeyen hücrenin sıfır sayılmasıyla hesaba hiç alınmaması arasındaki farkın ölçülmesi: aynı yordam, tek satır değişiklikle, aynı 410 eğitim etkileşiminden iki ayrı sıralama üretiyor. Atlayan kurulum dört etkenle 0,7006 isabet@5 veriyor ve 0,6527'lik tabanı geçiyor ama 24 kalemin yalnız 9'unu gösteriyor; sıfır sayan kurulum sekiz etkenle 0,2395'e düşerken 20 kalem gösteriyor ve ilk beş listelerinin en çok gösterilen beş kaleme düşen payını 0,7868'den 0,4467'ye indiriyor. Etken sayısı ayar değişkenidir, altı aday denenmiştir ve iki kurulumun ilk beşlerinin ortak kalem sayısı 4,02'den 0,86'ya iniyor.

Önceki ders benzerliği doğrudan ortak gözlemden kurdu: ortak kalemi olmayan iki abone arasında
benzerlik tanımlı değildi ve seyreklik yükseldikçe 167 sınav abonesinin 105'i komşusuz kaldı. Oysa
biri taksitlendirmeye, öbürü borç yapılandırmaya başvurmuş iki abone aynı ödeme davranışını
taşıyor olabilir; komşuluk yordamı bunu göremez, çünkü baktığı tek şey hücrelerin çakışmasıdır.

**Dizey ayrıştırma** bu kısıtı kaldırır: her abone ve her kalem az sayıda **gizli etken** üzerinde
bir vektörle temsil edilir ve bir hücrenin tahmini iki vektörün çarpımıdır. Ortak kalemi olmayan iki
abone aynı etken yönünde yüksek değer alabilir, dolayısıyla benzerlik hücrelerden değil
**gösterimden** okunur. Tam dizeyin düşük ranklı yaklaşımı M27/K04'ün boyut azaltma konusunda
ölçüldü ve burada tekrarlanmaz. Eklenen tek şey **eksik girdidir**, ve bu tek şey bir karar
doğurur: 8.640 hücrenin 8.230'u boş, ve boş hücre hesaba **sıfır olarak mı giriyor**, yoksa **hiç
girmiyor mu**. Bu dersin ölçtüğü şey o karardır.

- **ON30.** Kurgu küme, ayırma kuralı, taban çizgisi ve ölçüt önceki iki dersten aynen sürer:
  360 abone, 24 kalem, 410 eğitim etkileşimi, 167 sınav abonesi, ölçüt **isabet@5**, taban
  **en çok seçilen kalem sırası**.
- **ON31.** Ayrıştırma **modeldir** ve ders içinde yalnız standart kitaplıkla yazılır: abone dizeyi
  $P$ ile kalem dizeyi $Q$ **dönüşümlü** güncellenir ve her adımda **cezalı en küçük kareler**
  kapalı biçimde çözülür; M27/K03'ün eğim inişi tekrarlanmaz.
- **ON32.** İki kurulumun tek farkı, güncellemede **hangi hücrelerin toplama girdiğidir**.
  **Sıfır sayan** kurulumda satırın bütün 24 hücresi girer ve gözlenmeyenlerin hedefi 0'dır.
  **Atlayan** kurulumda yalnız gözlenen hücreler girer ve gözlenmeyen hiç yazılmaz.
- **ON33.** Ceza katsayısı **her iki kurulumda 1,0**'dır ve süpürülmez; ölçülen şey ceza
  katsayısının değil gözlenmeyen hücre kararının farkıdır.
- **ON34.** Etken sayısı $f$ bir **ayar değişkenidir**; **altı aday** denenmiştir (1, 2, 3, 4, 6, 8).
  Parametre sayısı $384f$, gözlenen etkileşim 410'dur; $f=2$'den itibaren parametre sayısı gözlem
  sayısını geçer.
- **ON35.** Dönüşümlü güncelleme **10 tur** sürer ve iki kurulum aynı başlangıçtan başlar. Küçük
  kare dizgeler yok etmeyle çözülür; köşegen için $10^{-12}$ eşiği yazılmıştır, çünkü kayan noktalı
  eşitlik sınanmaz.
- **ON36.** İki hata basılır: **gözlenen hücre hatası** 410 dolu hücrede, **tüm hücre hatası**
  8.640 hücrenin tamamında, ikisi de kök ortalama kare sapmadır. Her kurulum bunlardan birini
  küçültmek üzere kurulmuştur.
- **ON37.** **Gösterilen kalem sayısı** ve **ilk beş listelerinin en çok gösterilen beş kaleme düşen
  payı** kursun üçüncü sayısıdır; gösterilmeyen kalem bir sonraki dönemin verisine girmez.

## Tek Satır Fark: Hangi Hücreler Hesaba Giriyor

İlk blok kurguyu ve ayırmayı önceki derslerdeki biçimiyle kurar; sayılar değişmez.

```python
# Kurgu katalog birinci dersten gelir; burada yalniz kalemin alani ve taban payi gerekir.
TOHUM, M32, N_ABONE = 20260218, 0xFFFFFFFF, 360
KALEM = [("odeme", 0.90), ("bildirim", 0.85), ("bildirim", 0.78), ("odeme", 0.62),
         ("olcum", 0.55), ("bildirim", 0.50), ("odeme", 0.44), ("sozlesme", 0.40),
         ("olcum", 0.36), ("bildirim", 0.32), ("odeme", 0.28), ("sozlesme", 0.25),
         ("olcum", 0.22), ("tesisat", 0.19), ("olcum", 0.16), ("sozlesme", 0.14),
         ("tesisat", 0.12), ("sozlesme", 0.10), ("olcum", 0.09), ("sozlesme", 0.08),
         ("tesisat", 0.07), ("odeme", 0.06), ("bildirim", 0.05), ("tesisat", 0.04)]
KESIM = {
    "tasarruf": {"odeme": 0.5, "olcum": 1.7, "sozlesme": 0.6, "bildirim": 1.5, "tesisat": 0.6},
    "odeme":    {"odeme": 1.9, "olcum": 0.5, "sozlesme": 0.6, "bildirim": 1.1, "tesisat": 0.3},
    "isyeri":   {"odeme": 0.7, "olcum": 0.9, "sozlesme": 1.6, "bildirim": 0.7, "tesisat": 1.9},
    "yeni":     {"odeme": 0.8, "olcum": 0.7, "sozlesme": 1.8, "bildirim": 1.3, "tesisat": 0.7}}
KESIM_AD, N_KALEM = list(KESIM), len(KALEM)


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


ABONE, ETKILESIM = [], {}
for i in range(N_ABONE):
    r = uretec(TOHUM + 7919 * i)
    a, kesim = 20001 + i, KESIM_AD[int(r() * 4)]
    etkinlik = 0.35 + 1.15 * r() ** 1.6
    ABONE.append(a)
    for j, (alan, pay) in enumerate(KALEM):
        egilim = min(0.95, KESIM[kesim][alan] * pay * etkinlik * 0.55)
        if r() < min(0.95, pay ** 0.55 * 0.72):
            if r() < egilim:
                ETKILESIM[(a, j)] = r()
                if r() < 0.32:
                    r()
        else:
            r(), r(), r()

KAYIT, EGIT, AYRI = {}, {}, {}
for (a, j), damga in ETKILESIM.items():
    KAYIT.setdefault(a, []).append((damga, j))
GORULEN = {a: set() for a in ABONE}
for a, lst in KAYIT.items():
    lst.sort()
    if len(lst) >= 2:
        AYRI[a] = lst[-1][1]
        lst = lst[:-1]
    for damga, j in lst:
        EGIT[(a, j)] = 1
        GORULEN[a].add(j)

SINAV = sorted(AYRI)
PAY = [sum(1 for (a, j) in EGIT if j == jj) for jj in range(N_KALEM)]
KGOR = {j: set(a for a in ABONE if j in GORULEN[a]) for j in range(N_KALEM)}


def olc(puan, k=5):
    isabet, sira, gosterilen = 0, 0, set()
    for a in SINAV:
        s = puan(a)
        aday = sorted((j for j in range(N_KALEM) if j not in GORULEN[a]),
                      key=lambda j: (-s[j], j))
        gosterilen.update(aday[:k])
        p = aday.index(AYRI[a])
        isabet, sira = isabet + (p < k), sira + p + 1
    return isabet / len(SINAV), sira / len(SINAV), len(gosterilen)


print("egitim", len(EGIT), "etkilesim -- bos hucre", N_ABONE * N_KALEM - len(EGIT),
      "-- sinav abonesi", len(SINAV))
print("taban -- en cok secilen kalem: isabet@5 %.4f, ort sira %.2f, gosterilen %d/24"
      % olc(lambda a: PAY))
```

```
egitim 410 etkilesim -- bos hucre 8230 -- sinav abonesi 167
taban -- en cok secilen kalem: isabet@5 0.6527, ort sira 4.74, gosterilen 9/24
```

İki kurulum arasındaki fark `sifir_say` bayrağının açtığı tek toplamdır. Bayrak açıkken kare dizge
bütün kalemler üzerinden kurulur ve her abone için aynıdır; kapalıyken yalnız abonenin gözlenen
kalemleri üzerinden. Hedef vektörü ikisinde de aynıdır, çünkü sıfır hedefli hücreler toplama katkı
vermez.

```python
def coz(A, b):                     # kucuk kare dizgede yok etme; f en cok 8
    n = len(b)
    M = [A[i][:] + [b[i]] for i in range(n)]
    for i in range(n):
        p = max(range(i, n), key=lambda t: abs(M[t][i]))
        M[i], M[p] = M[p], M[i]
        if abs(M[i][i]) < 1e-12:   # esik: ceza terimi kosegeni sifirdan uzak tutar
            continue
        d = M[i][i]
        for k in range(i, n + 1):
            M[i][k] /= d
        for t in range(n):
            if t != i and M[t][i]:
                c = M[t][i]
                for k in range(i, n + 1):
                    M[t][k] -= c * M[i][k]
    return [M[i][n] for i in range(n)]


def ayristir(f, sifir_say, tur=10, ceza=1.0):
    # MODELDIR: donusumlu guncelleme ile dizey ayristirma, yalniz standart kitaplik.
    r = uretec(TOHUM + 5100 + f)
    P = {a: [0.1 + 0.2 * r() for _ in range(f)] for a in ABONE}
    Q = [[0.1 + 0.2 * r() for _ in range(f)] for _ in range(N_KALEM)]
    bos = [[0.0] * f for _ in range(f)]
    for _ in range(tur):
        G = ([[sum(q[x] * q[y] for q in Q) for y in range(f)] for x in range(f)]
             if sifir_say else bos)
        for a in ABONE:
            idx = GORULEN[a]
            A = [[G[x][y] + (0 if sifir_say else sum(Q[j][x] * Q[j][y] for j in idx))
                  + (ceza if x == y else 0) for y in range(f)] for x in range(f)]
            P[a] = coz(A, [sum(Q[j][x] for j in idx) for x in range(f)])
        H = ([[sum(P[a][x] * P[a][y] for a in ABONE) for y in range(f)] for x in range(f)]
             if sifir_say else bos)
        for j in range(N_KALEM):
            us = KGOR[j]
            A = [[H[x][y] + (0 if sifir_say else sum(P[a][x] * P[a][y] for a in us))
                  + (ceza if x == y else 0) for y in range(f)] for x in range(f)]
            Q[j] = coz(A, [sum(P[a][x] for a in us) for x in range(f)])
    return P, Q


def tahmin(P, Q):
    return lambda a: [sum(P[a][x] * Q[j][x] for x in range(len(Q[0])))
                      for j in range(N_KALEM)]


def hatalar(P, Q):
    f, go, ga = len(Q[0]), 0.0, 0.0
    for a in ABONE:
        for j in range(N_KALEM):
            d = (1.0 if j in GORULEN[a] else 0.0) - sum(P[a][x] * Q[j][x]
                                                        for x in range(f))
            ga += d * d
            if j in GORULEN[a]:
                go += d * d
    return (go / len(EGIT)) ** 0.5, (ga / (N_ABONE * N_KALEM)) ** 0.5


def ilk5(puan, a):
    s = puan(a)
    return set(sorted((j for j in range(N_KALEM) if j not in GORULEN[a]),
                      key=lambda j: (-s[j], j))[:5])


for ad, etiket in ((True, "sifir sayilir"), (False, "atlanir     ")):
    P, Q = ayristir(3, ad)
    ho, ha = hatalar(P, Q)
    print(f"f=3, gozlenmeyen {etiket}: isabet@5 {olc(tahmin(P, Q))[0]:.4f}  "
          f"gozlenen hucre hatasi {ho:.4f}  tum hucre hatasi {ha:.4f}")
```

```
f=3, gozlenmeyen sifir sayilir: isabet@5 0.4731  gozlenen hucre hatasi 0.7168  tum hucre hatasi 0.1614
f=3, gozlenmeyen atlanir     : isabet@5 0.6826  gozlenen hucre hatasi 0.2125  tum hucre hatasi 0.5055
```

Atlayan kurulumun gözlenen hücre hatası **0,2125**, sıfır sayanınki **0,7168** — üç katından fazla.
Tüm hücre hatasında sıra tersine dönüyor: sıfır sayan 0,1614, atlayan 0,5055. Her kurulum
küçültmeye çalıştığı toplamı küçültüyor ve öbürünün ölçüsünde kaybediyor: atlayan kurulum
gözlenmeyenler hakkında hiçbir kısıt görmediği için oralarda 0,5 civarında bir değer bırakıyor,
sıfır sayan kurulum 8.230 boş hücreyi 0'a çekerken 410 dolu hücreyi 1'e çekecek kapasite
bulamıyor.

Asıl sayı üçüncüsüdür. **Geri kurma hatası küçük olan kurulum daha kötü sıralama veriyor:**
atlayan 0,6826, sıfır sayan 0,4731.

## Etken Sayısı Bir Ayar Değişkenidir

Etken sayısı altı aday üzerinde süpürülür; yanına parametre sayısı, iki hata, gösterilen kalem
sayısı, taban listesiyle örtüşme ve iki kurulumun **birbiriyle** örtüşmesi basılır.

```python
TABAN5 = {a: ilk5(lambda x: PAY, a) for a in SINAV}
print(f"{'f':>2} {'par':>5} | {'A isb':>6} {'A gozl':>7} {'A tum':>6} {'A gst':>5} {'A tbn':>5}"
      f" | {'B isb':>6} {'B gozl':>7} {'B tum':>6} {'B gst':>5} {'B tbn':>5} | {'A~B':>5}")
for f in (1, 2, 3, 4, 6, 8):
    sat, top = [f"{f:>2} {(N_ABONE + N_KALEM) * f:>5}"], []
    for ad in (True, False):
        P, Q = ayristir(f, ad)
        pu = tahmin(P, Q)
        ho, ha = hatalar(P, Q)
        isb, sira, gst = olc(pu)
        L = {a: ilk5(pu, a) for a in SINAV}
        top.append(L)
        sat.append(f"| {isb:>6.4f} {ho:>7.4f} {ha:>6.4f} {gst:>5} "
                   f"{sum(len(L[a] & TABAN5[a]) for a in SINAV) / len(SINAV):>5.2f}")
    sat.append(f"| {sum(len(top[0][a] & top[1][a]) for a in SINAV) / len(SINAV):>5.2f}")
    print(" ".join(sat))
```

```
 f   par |  A isb  A gozl  A tum A gst A tbn |  B isb  B gozl  B tum B gst B tbn |   A~B
 1   384 | 0.6707  0.8377 0.1930    10  4.23 | 0.6707  0.2161 0.5207     9  4.34 |  4.02
 2   768 | 0.6048  0.7667 0.1760    11  4.16 | 0.6766  0.2124 0.5072     9  4.37 |  3.65
 3  1152 | 0.4731  0.7168 0.1614    12  3.43 | 0.6826  0.2125 0.5055     9  4.35 |  3.10
 4  1536 | 0.4251  0.6591 0.1479    15  2.68 | 0.7006  0.2115 0.5000     9  4.31 |  2.60
 6  2304 | 0.3593  0.5466 0.1263    20  1.45 | 0.6886  0.2113 0.4940     9  4.46 |  1.44
 8  3072 | 0.2395  0.4758 0.1066    20  0.82 | 0.6826  0.2107 0.4937     9  4.54 |  0.86
```

Son sütun dersin başlığıdır. Bir etkende iki kurulumun ilk beş listeleri **4,02 kalemi** paylaşıyor,
sekiz etkende **0,86**. Aynı veri, aynı yordam, aynı ceza, aynı başlangıç — ve tek satırlık bir fark
listelerin neredeyse tamamını değiştiriyor. Gözlenmeyen hücre kararı bir uygulama ayrıntısı değil,
**modelin ne öğrendiğinin tanımıdır**.

Sıfır sayan kurulum etken sayısıyla bozuluyor: 0,6707'den 0,2395'e. Nedeni ikinci sütunda duruyor.
Parametre sayısı $384f$; bir etkende 384, gözlenen etkileşim ise 410. **İki etkenden itibaren
parametre sayısı gözlem sayısını geçiyor** ve model 8.230 sıfırın arasından abone başına istisna
oymaya başlıyor. Taban listesiyle örtüşme 4,23'ten 0,82'ye iniyor: liste tabandan kopuyor, ama
koptuğu yer doğru yer değil.

Atlayan kurulum etken sayısına neredeyse duyarsız: en iyisi dört etkende **0,7006** — tabandan
**0,0479**, önceki dersin en iyi komşuluk kurulumundan 0,0060 yukarıda. Nedeni yapısaldır:
gözlenmeyen hücreye hiç bakılmadığı için fazladan etkenlerin yanlış öğrenebileceği bir şey yok ve
bir abonenin sıralaması gizli etken uzayında kendi kalemlerine yakın duran kalemlerden ibaret
kalıyor. Bu, önceki dersin öğe temelli komşuluğunun etkenler üzerinden yazılmış hâlidir.

## İki Sıralamanın Gösterdiği Katalog

İsabet iki kurulumu bir yönde sıralıyor. Kursun üçüncü sayısı, yani gösterilen kalem, öbür yönde
sıralıyor. Her iki kurulumun ilk beş listeleri sayılır ve taban çizgisiyle yan yana konur.

```python
def dagilim(puan):
    say = [0] * N_KALEM
    for a in SINAV:
        for j in ilk5(puan, a):
            say[j] += 1
    d = sorted(say, reverse=True)
    return sum(1 for v in say if v == 0), d[0], sum(d[:5]) / sum(d)


print(f"{'kurulum':>13} {'f':>2} {'hic gosterilmeyen':>18} {'en cok gosterilen':>18} "
      f"{'ilk 5 kalemin payi':>19}")
for etiket, f, ad in (("sifir sayilir", 1, True), ("sifir sayilir", 8, True),
                      ("atlanir", 1, False), ("atlanir", 8, False)):
    print("%13s %2d %18d %18d %19.4f"
          % ((etiket, f) + dagilim(tahmin(*ayristir(f, ad)))))
print("%13s %2s %18d %18d %19.4f" % (("taban", "--") + dagilim(lambda a: PAY)))
```

```
      kurulum  f  hic gosterilmeyen  en cok gosterilen  ilk 5 kalemin payi
sifir sayilir  1                 14                150              0.7904
sifir sayilir  8                  4                 84              0.4467
      atlanir  1                 15                146              0.7940
      atlanir  8                 15                146              0.7856
        taban --                 15                146              0.7868
```

Atlayan kurulum her iki etken sayısında da taban çizgisiyle **aynı** kataloğu gösteriyor: 15 kalem
hiç görünmüyor, en çok gösterilen kalem 167 abonenin 146'sına çıkıyor ve gösterimlerin **0,7856'sı**
beş kaleme düşüyor. En yüksek isabeti veren kurulum kataloğun görünen kısmını hiç genişletmiyor;
taban listesini biraz yeniden sıralamaktan ibaret.

Sıfır sayan kurulum sekiz etkenle bunun tersini yapıyor: hiç gösterilmeyen kalem **15'ten 4'e**,
en çok gösterilen kalemin ulaştığı abone 146'dan 84'e, ilk beş kalemin payı 0,7904'ten
**0,4467'ye** iniyor. Kataloğun kuyruğunu yukarı iten tek şey gözlenmeyen hücreyi sıfır saymaktır,
çünkü popüler kalemlere ait sıfırlar da toplama girer ve popülerliğin yönü bastırılır. Bedeli
isabette ödeniyor: 0,2395, tabanın 0,4132 altında.

İki sayı arasında seçim yapılmıyor; kurulum seçildiğinde ikisi birden belirleniyor. Gösterilmeyen
kalem seçilmez, seçilmeyen kalem bir sonraki dönemin eğitim kümesine girmez: bugün 15 kalemi hiç
göstermeyen bir kurulum, yarınki 410 etkileşimin hangi kalemlerden geleceğine de karar vermiştir.

## Özet

- Dizey ayrıştırma her aboneyi ve her kalemi az sayıda gizli etkene yerleştirir; ortak kalemi
  olmayan iki abone aynı etken yönünde buluşabilir. Eksik girdili dizeyde tek karar gözlenmeyen
  hücrenin ne sayıldığıdır ve yordamın geri kalanı iki kurulumda birebir aynıdır.
- Üç etkende atlayan kurulumun gözlenen hücre hatası 0,2125, sıfır sayanınki 0,7168; tüm hücre
  hatasında sıra tersine döner (0,5055 ve 0,1614). Küçük hata daha iyi sıralama demek değildir.
- Etken sayısı bir ayar değişkenidir ve altı aday denenmiştir: sıfır sayan kurulum 0,6707'den
  0,2395'e bozulur, atlayan kurulum en iyisini dört etkende (0,7006) verir.
- İki kurulumun ilk beş listelerinin ortak kalem sayısı bir etkende 4,02, sekiz etkende 0,86'dır:
  aynı veriden iki ayrı sıralama.
- Kapsama ters yönde hareket eder: atlayan kurulum taban çizgisiyle aynı 15 kalemi hiç göstermez;
  sıfır sayan kurulum bunu 4'e indirir ve ilk beş kalemin payını 0,7868'den 0,4467'ye çeker.

## Sonraki Adım

Dört derste öneri hep aynı yerden üretildi: **var olan etkileşimlerden**. Taban çizgisi eğitimde
seçilmiş kalemleri saydı, içerik temelli kurulum abonenin seçtiklerinden profil çıkardı, komşuluk
iki abonenin ortak seçimini aradı, ayrıştırma 410 dolu hücreyi etkenlere yerleştirdi. Dördünün de
sessiz varsayımı, aboneden en az bir etkileşimin gelmiş olmasıdır. Oysa aynı kurguda 360 abonenin
80'inin hiçbir etkileşimi yok ve son tablodaki 15 kalem hiçbir aboneye gösterilmiyor; bu iki grup
için dört yöntemin de üreteceği şey aynıdır. Sonraki ders bu iki boşluğu adıyla ele alır — hiç
etkileşimi olmayan abone ve hiç gösterilmemiş kalem — ve her çözümün kaç aboneyi, kaç kalemi
kapsama aldığını ve karşılığında hangi ölçüden ne verdiğini sayar.
