İçeriğe geç
academia.sh

Ders 09 / 14

İçerik Temelli Öneri

Kalemin özniteliklerinden abone profili çıkaran önerinin ölçülmesi: on bir bileşenli ikili öznitelik vektörüyle 360 abonenin 280'ine profil kurulur, 80'i için hiç öneri üretilemez. İlk beş isabet 0,4431 ile 0,6527'lik popülerlik tabanının altında kalır, ama katalog kapsaması 9 yerine 24'tür. Bedeli benzeşmedir: ilk beş listenin iç benzerliği 0,6769 ve listedeki kalemlerin 0,715'i tek bir alandan gelir. Hiç gösterilmemiş yeni bir kalem 280 abonenin tamamında sıralanır, 191'inin ilk onuna girer ve ortalama konumu 25 kalem içinde 11,55'tir; aynı kalem popülerlik sıralamasında sonuncudur.

İçindekiler

Önceki dersin tabanı ilk beş isabetini 0,6527’ye çıkardı, ama bunu kataloğun 24 kaleminden yalnız 9’unu göstererek yaptı ve hiç etkileşimi olmayan 80 aboneye herkese söylediğinin aynısını söyledi. İki eksik de aynı yerden geliyor: taban yalnız etkileşim sayılarına bakıyor, kalemin ne olduğuna bakmıyor.

Katalogda kalem başına yazılı bilgi var: hangi alana ait olduğu, hangi kanaldan yürüdüğü, ücretli olup olmadığı, taahhüt ve randevu gerektirip gerektirmediği. Bu ders o sütunlardan bir benzerlik kurar, aboneyi seçtiği kalemlerin ortalaması olarak tarif eder ve iki sayıyı ölçer: kaç abone için hiç öneri üretilemiyor, ve üretilen öneriler birbirine ne kadar benziyor.

  • ON9. Kurgu ve tohum önceki dersle aynıdır; dizey, ayırma ve popülerlik tabanı aynen yeniden kurulur ve aynı sayıları verir.
  • ON10. Öznitelik vektörü on bir bileşenlidir: beş alan, üç kanal ve üç ikili bayrak. Bileşenler 0/1’dir ve vektör birim uzunluğa getirilir.
  • ON11. Abone profili, eğitim kümesinde seçtiği kalemlerin öznitelik vektörlerinin toplamının birim uzunluğa getirilmiş halidir. Puanlar kullanılmaz; profil örtük sinyalden gelir.
  • ON12. İki birim vektörün benzerliği iç çarpımlarıdır ve 0 ile 1 arasındadır. Eşitlik durumunda katalog sırası bozar; kayan noktalı değerler doğrudan karşılaştırılmaz, sıralama anahtarı olarak kullanılır.
  • ON13. Kapsama iki ayrı sayıdır: kaç aboneye öneri üretilebildiği, ve kaç ayrı kalemin en az bir abonenin listesine girdiği.
  • ON14. Bir listenin iç benzerliği, listedeki bütün kalem ikililerinin ortalama benzerliğidir.
  • ON15. Sonda katalogda yeni bir kalem vardır: öznitelikleri yazılıdır, hiç gösterilmemiştir ve hiçbir etkileşimi yoktur.

Dizeyi Yeniden Kurmak

Ölçüm aynı veri üstünde yapılmazsa iki dersin sayıları karşılaştırılamaz. Aşağıdaki blok kurguyu, ayırmayı ve popülerlik tabanını aynı tohumla yeniden kurar; iki satırlık çıktısı önceki dersin seyreklik ve isabet sayılarıyla birebir aynı olmalıdır.

# ORTAK -- KURGUDUR. Onceki dersin dizeyi ayni tohumla yeniden kurulur; bu kez
# katalogun oznitelik sutunlari da okunacak.
TOHUM, M32 = 20260218, 0xFFFFFFFF


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


KALEM = [  # (ad, alan, kanal, ucretli, taahhut, randevu, taban_pay)
    ("otomatik_odeme_talimati", "odeme", "cevrimici", 0, 0, 0, 0.90),
    ("e_fatura_gecisi", "bildirim", "cevrimici", 0, 0, 0, 0.85),
    ("odeme_hatirlatma_sms", "bildirim", "cevrimici", 0, 0, 0, 0.78),
    ("taksitlendirme", "odeme", "sube", 0, 1, 0, 0.62),
    ("uzaktan_okuma_basvurusu", "olcum", "saha", 0, 1, 1, 0.55),
    ("kesinti_uyari_aboneligi", "bildirim", "cevrimici", 0, 0, 0, 0.50),
    ("borc_yapilandirma", "odeme", "sube", 0, 1, 0, 0.44),
    ("adres_guncelleme", "sozlesme", "cevrimici", 0, 0, 0, 0.40),
    ("sayac_degisimi", "olcum", "saha", 1, 0, 1, 0.36),
    ("tuketim_raporu_aboneligi", "bildirim", "cevrimici", 0, 0, 0, 0.32),
    ("fatura_itiraz_kaydi", "odeme", "sube", 0, 0, 0, 0.28),
    ("abonelik_devri", "sozlesme", "sube", 0, 0, 0, 0.25),
    ("kacak_kontrol_randevusu", "olcum", "saha", 0, 0, 1, 0.22),
    ("tesisat_bakim_paketi", "tesisat", "saha", 1, 1, 1, 0.19),
    ("ikinci_sayac_talebi", "olcum", "saha", 1, 0, 1, 0.16),
    ("isyeri_tarifesine_gecis", "sozlesme", "sube", 0, 1, 0, 0.14),
    ("basinc_duzenleyici_montaji", "tesisat", "saha", 1, 0, 1, 0.12),
    ("bahce_sulama_tarifesi", "sozlesme", "sube", 0, 1, 0, 0.10),
    ("sayac_yeri_degisikligi", "olcum", "saha", 1, 0, 1, 0.09),
    ("ortak_alan_paylasim_kaydi", "sozlesme", "sube", 0, 1, 0, 0.08),
    ("tesisat_uygunluk_raporu", "tesisat", "saha", 1, 0, 1, 0.07),
    ("gecikme_faizi_muafiyeti", "odeme", "sube", 0, 0, 0, 0.06),
    ("mobil_erisim_izni", "bildirim", "cevrimici", 0, 0, 0, 0.05),
    ("ek_hat_tesisati", "tesisat", "saha", 1, 1, 1, 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 = list(KESIM)
rk = uretec(TOHUM + 101)
KALITE = [0.25 + 0.70 * rk() for _ in KALEM]

N_ABONE, N_KALEM = 360, len(KALEM)
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, (ad, alan, kanal, uc, ta, ra, 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):     # gosterildi mi
            if r() < egilim:                         # secildi mi
                ETKILESIM[(a, j)] = r()
                if r() < 0.32:
                    r()                              # puan cekimi: burada okunmuyor
        else:
            r(), r(), r()

EGIT, AYRI, GORULEN, kayit = {}, {}, {}, {}
for (a, j), damga in ETKILESIM.items():
    kayit.setdefault(a, []).append((damga, j))
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.setdefault(a, set()).add(j)
pay = [0] * N_KALEM
for (a, j) in EGIT:
    pay[j] += 1
sirali = sorted(range(N_KALEM), key=lambda j: -pay[j])


def isabet(oner, K):
    return sum(1 for a in AYRI if AYRI[a] in oner(a)[:K]) / len(AYRI)


def taban(a):
    return [j for j in sirali if j not in GORULEN.get(a, set())]


print("etkilesim", len(ETKILESIM), " seyreklik",
      round(1 - len(ETKILESIM) / (N_ABONE * N_KALEM), 4))
print("ayrilmis abone", len(AYRI), " taban ilk 5 isabet", round(isabet(taban, 5), 4))
etkilesim 577  seyreklik 0.9332
ayrilmis abone 167  taban ilk 5 isabet 0.6527

İki satır önceki dersle birebir aynı: 577 etkileşim, 0,9332 seyreklik, 167 ayrılmış abone ve 0,6527 taban isabeti. Bu tekrar bir tören değil, ölçümün ön koşulu: iki yöntemin sayısı ancak aynı ayırma, aynı ayrılmış küme ve aynı taban üstünde okunduğunda karşılaştırılabilir. Kurgu aynı tohumdan yeniden üretildiği için aradaki her fark yöntemden gelir.

Öznitelikten Profile

Her kalem on bir bileşenli bir vektöre dönüşür ve birim uzunluğa getirilir; böylece çok özniteliği olan kalem yalnız bu yüzden öne çıkmaz. Ücretli, taahhütlü ve randevulu bir saha kalemi altı bileşeninde 1 taşır, ücretsiz bir çevrimiçi kalem yalnız ikisinde; ölçekleme olmasaydı birincisi her profile daha yakın görünürdü. Bileşenler ikili olduğu için çok sayıda eşit benzerlik çıkar, ve eşitlik katalog sırasıyla bozulur; bu keyfi bir kuraldır ve sonucu koşumdan koşuma sabit tutmak için yazılmıştır.

Abonenin profili, seçtiği kalemlerin vektörlerinin toplamıdır: iki saha başvurusu yapmış bir abonenin profili saha yönünde uzar. Öneri, profile en yakın ve daha önce seçilmemiş kalemleri sıralamaktır. Abonenin hiç seçimi yoksa toplanacak vektör yoktur ve profil kurulamaz.

import math

ALAN = ["odeme", "olcum", "sozlesme", "bildirim", "tesisat"]
KANAL = ["cevrimici", "saha", "sube"]


def oznitelik(k):
    v = [1.0 if k[1] == x else 0.0 for x in ALAN]
    v += [1.0 if k[2] == x else 0.0 for x in KANAL]
    v += [float(k[3]), float(k[4]), float(k[5])]
    n = math.sqrt(sum(x * x for x in v))
    return [x / n for x in v]


def benzerlik(u, v):
    return sum(x * y for x, y in zip(u, v))


OZ = [oznitelik(k) for k in KALEM]
BOYUT = len(OZ[0])

PROFIL = {}
for a in ABONE:
    gor = GORULEN.get(a, set())
    if not gor:
        continue                                   # profil kurulamaz
    p = [sum(OZ[j][d] for j in gor) for d in range(BOYUT)]
    n = math.sqrt(sum(x * x for x in p))
    PROFIL[a] = [x / n for x in p]


def icerik(a):
    if a not in PROFIL:
        return []                                  # oneri uretilemiyor
    return sorted((j for j in range(len(OZ)) if j not in GORULEN.get(a, set())),
                  key=lambda j: (-benzerlik(PROFIL[a], OZ[j]), j))


def kapsama(oner, K=5):
    return len({j for a in AYRI for j in oner(a)[:K]})


def ic_benzerlik(oner, K=5):
    t = n = 0
    for a in AYRI:
        lst = oner(a)[:K]
        for x in range(len(lst)):
            for y in range(x + 1, len(lst)):
                t += benzerlik(OZ[lst[x]], OZ[lst[y]])
                n += 1
    return t / n


print("profil kurulan abone", len(PROFIL), "/", N_ABONE,
      " kurulamayan", N_ABONE - len(PROFIL))
for K in (3, 5):
    print(f"ilk {K}: icerik {isabet(icerik, K):.4f}  taban {isabet(taban, K):.4f}")
print("katalog kapsamasi   icerik", kapsama(icerik), " taban", kapsama(taban), "/", N_KALEM)
print(f"ilk 5 ic benzerlik  icerik {ic_benzerlik(icerik):.4f}  taban {ic_benzerlik(taban):.4f}")
t = 0
for a in AYRI:
    alanlar = [KALEM[j][1] for j in icerik(a)[:5]]
    t += max(alanlar.count(x) for x in set(alanlar))
print("ilk 5 te en cok gecen alanin ortalama payi", round(t / len(AYRI) / 5, 4))
profil kurulan abone 280 / 360  kurulamayan 80
ilk 3: icerik 0.2874  taban 0.5509
ilk 5: icerik 0.4431  taban 0.6527
katalog kapsamasi   icerik 24  taban 9 / 24
ilk 5 ic benzerlik  icerik 0.6769  taban 0.3827
ilk 5 te en cok gecen alanin ortalama payi 0.715

İçerik temelli öneri tabanın altında kalıyor: ilk beş isabeti 0,4431, tabanın 0,6527’sinin 0,2096 gerisinde; ilk üçte fark daha büyük, 0,2874’e karşı 0,5509. Farkın kaynağı yöntemin ne gördüğüdür. Bir kalemin seçilme olasılığı kurguda iki çarpandan gelir: abonenin o alana eğilimi, ve kalemin kendi yaygınlığı. Öznitelik vektörü yalnız birincisini taşır; ikincisi, yani kaç abonenin o kalemi seçtiği, öznitelik sütunlarında hiç yazılı değil. Yöntem “bu abone neyi seçer” sorusunu “bu abonenin seçtiklerine ne benzer” sorusuyla değiştiriyor ve yaygınlığı düşürüyor.

Kapsama sütunu ters yöne bakıyor. Taban 167 abonenin listelerine yalnız 9 kalem sokuyordu; içerik temelli öneri 24 kalemin tamamını en az bir listeye sokuyor. Buna karşılık listeler kendi içlerinde daralıyor: ilk beşin iç benzerliği tabanda 0,3827 iken içerik temelli öneride 0,6769, ve ilk beşteki kalemlerin ortalama 0,715’i tek bir alandan geliyor. Saha başvurusu yapmış aboneye dört saha başvurusu daha öneriliyor. Katalog düzeyinde çeşitlilik artıyor, abone düzeyinde azalıyor, ve iki sayı ayrı ayrı yazılmazsa kapsama tek başına yanıltır.

Abone kapsaması kapsamanın öbür yarısı: 360 abonenin 280’ine profil kurulabiliyor, 80’ine hiç öneri üretilemiyor. Bu 80 abone bir sonraki dönem de hiçbir şey görmeyecek, hiçbir şey seçmeyecek ve satırları boş kalmaya devam edecek.

Üç sayı üç ayrı soruya yanıt veriyor ve hiçbiri diğerinin yerine geçmiyor. İsabet “ayrılmış kalem listede mi” diye soruyor ve içerik temelli yöntem burada kaybediyor. Katalog kapsaması “kaç kalem hiç görünmüyor” diye soruyor ve burada kazanıyor. İç benzerlik “listedeki beş kalem birbirinin tekrarı mı” diye soruyor ve burada kaybediyor. Yalnız isabeti yazan bir rapor yöntemi gereksiz gösterir, yalnız kapsamayı yazan bir rapor onu gereğinden iyi gösterir.

Yeni Kalem ve Yeni Abone

Soğuk başlangıç iki yönlüdür ve içerik temelli öneri ikisine iki ayrı yanıt verir. Katalogda hiç gösterilmemiş bir kalem düşünelim: etkileşim sayısı sıfır, ama öznitelikleri katalogla birlikte yazılmış. Bir de hiç etkileşimi olmayan bir abone düşünelim: öznitelikleri yok, çünkü öznitelik kalemin, abonenin değil.

# Kataloga hic gosterilmemis yeni bir kalem eklenir: hicbir etkilesimi yok,
# yalniz oznitelikleri var.
YENI = ("mobil_sayac_okuma", "olcum", "cevrimici", 0, 0, 0, 0.0)
OZ.append(oznitelik(YENI))
YJ = len(OZ) - 1

ilk5 = sum(1 for a in PROFIL if YJ in icerik(a)[:5])
ilk10 = sum(1 for a in PROFIL if YJ in icerik(a)[:10])
konum = sum(icerik(a).index(YJ) + 1 for a in PROFIL) / len(PROFIL)
print(f"{YENI[0]}: icerik temelli ilk 5 -> {ilk5} abone, ilk 10 -> {ilk10} abone")
print("ortalama konum", round(konum, 2), "/", len(OZ), " taban siralamasinda konum",
      len(OZ), "(etkilesim sayisi 0)")
print("profilsiz abone", N_ABONE - len(PROFIL), " icerik temelli oneri sayisi",
      sum(len(icerik(a)) for a in ABONE if a not in PROFIL),
      " tabanin verdigi", 5 * (N_ABONE - len(PROFIL)))
mobil_sayac_okuma: icerik temelli ilk 5 -> 13 abone, ilk 10 -> 191 abone
ortalama konum 11.55 / 25  taban siralamasinda konum 25 (etkilesim sayisi 0)
profilsiz abone 80  icerik temelli oneri sayisi 0  tabanin verdigi 400

Yeni kalem 280 abonenin tamamında sıralanıyor: hiç gösterilmemiş olmasına rağmen ortalama konumu 25 kalem içinde 11,55, ve 191 abonenin ilk onuna, 13 abonenin ilk beşine giriyor. Bir etkileşim sayısına dayanan sıralamada aynı kalem herkes için sonuncudur ve sonuncu kaldığı sürece gösterilmediği için etkileşim de toplayamaz. Öznitelik bu döngüyü kıran şeydir: kalem hakkında etkileşimden önce bilinen bir bilgi taşır.

Aynı yardım abone tarafında yok. Profilsiz 80 abone için içerik temelli yöntem toplam sıfır öneri üretiyor; kişiselleştirmesiz taban aynı abonelere 400 öneri veriyor, hepsi aynı beş kalem. Asimetri yöntemin tanımından geliyor: katalogda kalemin öznitelikleri yazılı, abonenin öznitelikleri değil. Abone hakkında bilinen tek şey geçmiş seçimleri, ve geçmiş seçimi olmayan abone hakkında bilinen hiçbir şey yok.

Bu dersin toplanan veri sayısı budur: 80 abone hiçbir öneri almıyor, ve alamadıkları için bir sonraki dönemin etkileşim dizeyine de hiçbir satır eklemiyorlar.

Özet

  • Öznitelik vektörü on bir bileşenlidir; abone profili seçtiği kalemlerin vektörlerinin birim uzunluğa getirilmiş toplamıdır ve 360 abonenin 280’ine kurulabilir.
  • İçerik temelli önerinin ilk beş isabeti 0,4431, ilk üç isabeti 0,2874’tür; popülerlik tabanı aynı ölçülerde 0,6527 ve 0,5509 verir. Öznitelik sütunları kalemin yaygınlığını taşımaz.
  • Katalog kapsaması 9’dan 24’e çıkar, ama listelerin iç benzerliği 0,3827’den 0,6769’a yükselir ve ilk beşteki kalemlerin 0,715’i tek bir alandan gelir.
  • Kapsama iki sayıdır: 80 abone için hiç öneri üretilemez, ve bu abonelere hiçbir şey gösterilmediği için satırları boş kalmaya devam eder.
  • Hiç gösterilmemiş yeni bir kalem 280 abonenin tamamında sıralanır, 191’inin ilk onuna girer ve ortalama konumu 11,55’tir; etkileşim sayısına dayanan sıralamada aynı kalem sonuncudur.

Sonraki Adım

İçerik temelli öneri iki kalemi, ikisinin öznitelik sütunları benzediği için yakın sayıyor. Bu yüzden yeni kalemi ilk günden sıralayabiliyor, ve bu yüzden bir aboneye hep aynı alandan beş kalem öneriyor. Ölçümde hiç kullanılmayan bir şey kaldı: abonelerin birbirine benzemesi. Aynı üç kalemi seçmiş iki abone, öznitelik sütunlarında hiçbir izi olmayan bir ortaklık taşır; birinin seçip diğerinin henüz seçmediği dördüncü kalem bir öneri adayıdır. Bir sonraki ders benzerliği kalemin özniteliklerinden değil etkileşim dizeyinin satır ve sütunlarından kurar, komşu sayısının sıralamayı ne kadar oynattığını ölçer, ve seyreklik arttıkça hiç komşu bulunamayan abone sayısını sayar.

İ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