Ders 12 / 14
Soğuk Başlangıç
Hiç etkileşimi olmayan abone ve hiç seçilmemiş kalem için önerinin kurulması: 360 abonenin 80'inin hiç, 113'ünün tek etkileşimi vardır ve tek etkileşim gizlenince 193 abone soğuk sayılır, 464 etkileşimlik eğitim kümesinde bir kalem hiç seçilmemiş ve sekiz kalem beşin altındadır. Popülerlik geri dönüşü 193 abonenin tamamını ısıtır ama hepsine aynı beş kalemi verir, öznitelik köprüsü tek soğuk kalemi 114 aboneye ulaştırır ama hiçbir soğuk aboneyi ısıtmaz, üç soruluk giriş 339 soruyla 71 aboneyi ısıtıp kapsamayı 5'ten 13 kaleme çıkarır ve ilk beş isabetini 0,5752'den 0,5487'ye düşürür.
İçindekiler
Dört derste öneri hep var olan etkileşimlerden üretildi: içerik temelli yaklaşım kalemin özniteliklerinden, işbirlikçi süzgeçleme komşu abonelerin geçmişinden, dizey ayrıştırma gizli etkenlerden. Üçünün de sessiz bir ortak koşulu vardı — abonenin dolu bir satırı olması. Satırı tümüyle boş olan abone ile sütunu tümüyle boş olan kalem için ne yapılacağı sorulmadı.
Bu dersin ölçtüğü şey bir doğruluk değil, ısıtmadır: kaç abone ve kaç kalem soğuk, ve her çözüm bunların kaçını öneri üretilebilir hale getiriyor. Her ısıtmanın bir bedeli vardır ve bedel aynı satırda sayılır.
- ON41. Kurgu birinci derste kurulan bloğun aynısıdır ve aynı sayıları verir: 360 abone, 24 hizmet kalemi, 8.640 hücre, tohum 20260218; 3.002 gösterim, 577 etkileşim, 218 puan.
- ON42. Soğuk abone, eğitim kümesinde hiç etkileşimi olmayan abonedir. Soğuk kalem, eğitim kümesinde hiç seçilmemiş kalemdir.
- ON43. Soğuk protokol ayırmayı değiştirir. Hiç etkileşimi olmayan abonenin doğru cevabı da yoktur ve ölçüye giremez. Tek etkileşimi olan abonenin o tek etkileşimi gizlenir: satırı boşalır, doğru cevabı bilinir. Geriye kalan etkileşimler eğitim kümesidir.
- ON44. Taban çizgisi, eğitimde en çok seçilen beş kalemi herkese sunmaktır. Birinci derste kurulan taban budur; soğuk abone için elde başka hiçbir bilgi olmadığından burada da o seçilir.
- ON45. Isıtma, bir çözümün soğuk aboneyi ya da soğuk kalemi öneri üretilebilir hale getirmesidir ve sayısı kaç abone, kaç kalemdir.
- ON46. Bedel üç sayıyla yazılır: sorulan soru sayısı, cevapsız kalan abone sayısı, ve önerilerin yayıldığı ayrı kalem sayısı.
- ON47. Üç soruluk giriş kurgudur: ilgilendiğiniz alan, ikinci alan, başvuru sıklığı. Cevaplama oranı 0,62’dir ve kurgunun bir parametresidir.
- ON48. Ölçüt ilk beş isabetidir; tanımı birinci derste kuruldu ve burada tekrarlanmaz.
Soğuk Olanı Saymak
# ORTAK -- KURGUDUR. Abone x hizmet kalemi etkilesim dizeyi ders icinde kurulur. # Gosterim, secim ve puan ayri ayri uretilir: bir kalem once GOSTERILIR, sonra # secilebilir, ancak secilirse puanlanabilir. 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 = { # kesimin alanlara egilimi; yalniz uretecin icinde kullanilir "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] # kalemin kendi doyuruculugu N_ABONE, N_KALEM = 360, len(KALEM) ABONE, GOSTERIM, ETKILESIM, PUAN, EGILIM = [], {}, {}, {}, {} 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) EGILIM[(a, j)] = egilim if r() < min(0.95, pay ** 0.55 * 0.72): # sunulmus mu GOSTERIM[(a, j)] = 1 if r() < egilim: # secilmis mi ETKILESIM[(a, j)] = r() # deger: sira damgasi if r() < 0.32: # puan birakmis mi ham = (0.16 + 0.50 * KESIM[kesim][alan] / 1.9 + 0.42 * KALITE[j] + 0.26 * (r() - 0.5)) PUAN[(a, j)] = max(1, min(5, int(round(ham * 5)))) else: r(), r(), r() kayit = {} for (a, j), damga in ETKILESIM.items(): kayit.setdefault(a, []).append((damga, j)) SIFIR = [a for a in ABONE if a not in kayit] TEKIL = sorted(a for a in kayit if len(kayit[a]) == 1) COKLU = [a for a in kayit if len(kayit[a]) >= 2] GIZLI = {a: kayit[a][0][1] for a in TEKIL} # SOGUK PROTOKOL: tek etkilesim gizlenir EGIT = dict(((a, j), 1) for a in COKLU for _, j in kayit[a]) secim = [0] * N_KALEM for (a, j) in EGIT: secim[j] += 1 SOGUK_K = [j for j in range(N_KALEM) if secim[j] == 0] AZ_K = sorted(range(N_KALEM), key=lambda j: (secim[j], j)) SIRALI = sorted(range(N_KALEM), key=lambda j: (-secim[j], j)) print(f"{N_ABONE} abone: {len(SIFIR)} sifir etkilesim, {len(TEKIL)} tek etkilesim, " f"{len(COKLU)} iki ve ustu") print(f"soguk abone {len(SIFIR) + len(TEKIL)}; olculebilen {len(TEKIL)} abone, " f"egitim kumesi {len(EGIT)} etkilesim") print(f"soguk kalem {len(SOGUK_K)}: {', '.join(KALEM[j][0] for j in SOGUK_K)}; " f"bes etkilesimin altinda {sum(1 for j in range(N_KALEM) if secim[j] < 5)} kalem") print("taban listesi (egitimde en cok secilen bes kalem):") for j in SIRALI[:5]: print(f" {KALEM[j][0]:26s} {secim[j]:3d}")
360 abone: 80 sifir etkilesim, 113 tek etkilesim, 167 iki ve ustu soguk abone 193; olculebilen 113 abone, egitim kumesi 464 etkilesim soguk kalem 1: mobil_erisim_izni; bes etkilesimin altinda 8 kalem taban listesi (egitimde en cok secilen bes kalem): e_fatura_gecisi 76 odeme_hatirlatma_sms 71 otomatik_odeme_talimati 58 taksitlendirme 46 uzaktan_okuma_basvurusu 31
Üç sayı üç ayrı abone kümesi tarif ediyor. 80 abonenin hiç etkileşimi yok; bu aboneler için elde ne bir geçmiş var ne de bir doğru cevap, dolayısıyla hiçbir ölçüye giremezler ama sisteme her gün gelirler. 113 abonenin tek etkileşimi var ve soğuk protokol o tek etkileşimi gizler: satırları boşalır, doğru cevapları elde kalır. Soğuk abone toplamı 193, yani 360 abonenin yarıdan biraz azı; ölçülebilen kısmı 113.
Kalem tarafı çok daha dar: eğitim kümesinde hiç seçilmemiş 1 kalem var, beş etkileşimin altında kalan 8 kalem. Taban listesi kataloğun eğriliğini olduğu gibi yansıtıyor — beş kalem 464 etkileşimin 282’sini topluyor. Soğuk olmak ile önerilmemek ayrı şeylerdir: önceki derslerde taban listesinin 24 kalemin 15’ini hiçbir aboneye önermediği ölçülmüştü, oysa o kalemlerin etkileşimi vardır ve soğuk değildirler; yalnız sıralamaya girmezler. Soğuk başlangıcın iki yüzü de aynı ağırlıkta değildir: bu kurguda soğuk abone sorunu soğuk kalem sorunundan çok büyüktür.
Kalemi Isıtmak: Öznitelik Köprüsü
Soğuk kalemin etkileşimi yoktur ama özniteliği vardır: hangi alana ait olduğu, hangi kanaldan yürüdüğü, ücretli mi, taahhüt mü istediği, randevu mu gerektirdiği. Köprü bu özniteliklerle soğuk kalemi sıcak komşularına bağlar ve kalem, o komşularla etkileşmiş abonelerin listesine girer.
import math ALAN = ["odeme", "olcum", "sozlesme", "bildirim", "tesisat"] KANAL = ["cevrimici", "saha", "sube"] def oz(j): """Kalem oznitelikleri: alan, kanal ve uc ikili bayrak. Etkilesim gerektirmez.""" ad, alan, kanal, uc, ta, ra, p = KALEM[j] return ([1.0 if alan == x else 0.0 for x in ALAN] + [1.0 if kanal == x else 0.0 for x in KANAL] + [float(uc), float(ta), float(ra)]) def benzer(i, j): x, y = oz(i), oz(j) return sum(p * q for p, q in zip(x, y)) / ( math.sqrt(sum(p * p for p in x) * sum(q * q for q in y)) + 1e-9) sicak = [j for j in range(N_KALEM) if secim[j] > 0] print("icerik temelli kopru; son sutun komsulariyla etkilesmis abone sayisi") for j in AZ_K[:4]: kom = sorted(sicak, key=lambda t: (-benzer(j, t), t))[:2] if j in kom: kom = [t for t in kom if t != j] + [sorted(sicak, key=lambda t: (-benzer(j, t), t))[2]] ulas = set(a for (a, t) in EGIT if t in kom) print(f" {KALEM[j][0]:24s}{secim[j]:2d} komsu: {KALEM[kom[0]][0]}, " f"{KALEM[kom[1]][0]} -> {len(ulas):>3}") print(f"kopru {len(SOGUK_K)}/{len(SOGUK_K)} soguk kalemi oneri havuzuna sokuyor, " f"0/{len(SIFIR) + len(TEKIL)} soguk aboneyi isitiyor")
icerik temelli kopru; son sutun komsulariyla etkilesmis abone sayisi mobil_erisim_izni 0 komsu: e_fatura_gecisi, odeme_hatirlatma_sms -> 114 tesisat_uygunluk_raporu 1 komsu: basinc_duzenleyici_montaji, tesisat_bakim_paketi -> 10 gecikme_faizi_muafiyeti 1 komsu: fatura_itiraz_kaydi, taksitlendirme -> 53 ek_hat_tesisati 1 komsu: tesisat_bakim_paketi, basinc_duzenleyici_montaji -> 10 kopru 1/1 soguk kalemi oneri havuzuna sokuyor, 0/193 soguk aboneyi isitiyor
Köprü soğuk kalem sorununu çözüyor: 1/1. Erişim genişliği ise komşunun kim olduğuna bağlı ve
bu, köprünün gizli bedelidir. mobil_erisim_izni en yakın komşuları çevrimiçi bildirim kalemleri
olduğu için 114 aboneye ulaşıyor; tesisat_uygunluk_raporu ile ek_hat_tesisati ise saha
tesisat kalemlerine komşu oldukları için 10’ar aboneye. Köprü, kalemi kendi komşularının
yaygınlığı kadar ısıtır — yaygın komşusu olan soğuk kalem hemen ısınır, seyrek komşusu olan soğuk
kalır. Kalemi ısıtmak, sütunun kendi popülerliğini değil, komşusununkini ödünç almaktır.
Son satır asıl sınırı yazıyor: köprü 0/193 soğuk aboneyi ısıtıyor. Kurguda kalemin özniteliği vardır, abonenin yoktur; abone hakkında bilinen tek şey geçmişidir ve soğuk abonenin geçmişi boştur. İçerik temelli yaklaşım soğuk başlangıcın yalnız bir yüzünü görür.
Aboneyi Isıtmak: Üç Soruluk Giriş
Abone tarafında iki seçenek kalır: tabana düşmek — herkese aynı beş kalemi sunmak — ya da abonenin kendisine sormak. İkincisi kayıtta olmayan veriyi üretir ve bedeli sorudur.
KESIMI = dict((20001 + i, KESIM_AD[int(uretec(TOHUM + 7919 * i)() * 4)]) for i in range(N_ABONE)) CEVAP = {} for a in TEKIL: # uc soru: alan, ikinci alan, etkinlik q = uretec(TOHUM + 555000 + a) if q() < 0.62: # cevaplama orani kurgudur s = sorted(KESIM[KESIMI[a]], key=lambda x: -KESIM[KESIMI[a]][x]) CEVAP[a] = (s[0], s[1], 0.35 + 1.15 * uretec(TOHUM + 7919 * (a - 20001))() ** 1.6) def taban(a): return SIRALI[:5] def giris(a, ucuncu=False): """Cevap verilmisse alan sirasi, verilmemisse taban listesi. MODELDIR.""" if a not in CEVAP: return SIRALI[:5] a1, a2, etkinlik = CEVAP[a] kat = etkinlik if ucuncu else 1.0 # ucuncu cevap her kalemi esit carpar return sorted(range(N_KALEM), key=lambda j: ( -kat * (secim[j] + 1) ** 0.35 * (3.0 if KALEM[j][1] == a1 else 1.8 if KALEM[j][1] == a2 else 1.0), j))[:5] print(f"uc soruluk giris: {3 * len(TEKIL)} soru soruldu, {len(CEVAP)} abone cevapladi, " f"{len(TEKIL) - len(CEVAP)} abone taban listesine dustu") for ad, f in (("taban (populerlik)", taban), ("giris, iki cevap", giris), ("giris, uc cevap", lambda a: giris(a, True))): isabet = sum(1 for a in TEKIL if GIZLI[a] in f(a)) / len(TEKIL) kaps = len(set(j for a in TEKIL for j in f(a))) print(f" {ad:<20} ilk bes isabet {isabet:.4f} kapsama {kaps:>2}/{N_KALEM}")
uc soruluk giris: 339 soru soruldu, 71 abone cevapladi, 42 abone taban listesine dustu taban (populerlik) ilk bes isabet 0.5752 kapsama 5/24 giris, iki cevap ilk bes isabet 0.5487 kapsama 13/24 giris, uc cevap ilk bes isabet 0.5487 kapsama 13/24
Üç çözümün ısıttığı artık yan yana okunabilir. Popülerlik geri dönüşü 193/193 aboneyi ısıtır ve 0/1 kalemi; öznitelik köprüsü 0/193 aboneyi ve 1/1 kalemi; üç soruluk giriş ölçülebilen 113 abonenin 71’ini ısıtır ve 0/1 kalemi. Hiçbiri iki yüzü birden ısıtmaz. Soğuk başlangıç tek bir sorun değildir; iki ayrı sorundur ve iki ayrı çözüm ister.
Bedeller de yan yana durur. Giriş için 339 soru soruldu, 42 abone hiç cevap vermeyip tabana düştü; cevaplama oranının 0,62 olması kurgunun bir seçimidir ve daha düşük bir oran ısıtılan abone sayısını doğrudan aşağı çeker. Üçüncü sorunun bedeli özel bir tür: başvuru sıklığı cevabı her kalemi aynı katsayıyla çarptığı için sıralamayı hiç değiştirmiyor, isabet de kapsama da iki cevaplı kurulumla birebir aynı çıkıyor. 113 abonenin her birine sorulan bu üçüncü soru karşılığında sistemin eline hiçbir sıralama değişikliği geçmiyor. Bir cevabın bilgi taşıması, o cevabın seçenekleri birbirinden ayırmasına bağlıdır.
Tabanın bedeli soruda değil, tekdüzeliktedir: 113 aboneye toplam 5 ayrı kalem önerildi. Giriş bu sayıyı 13’e çıkarıyor. Buna karşılık kayıttan okunan ilk beş isabeti tabanda 0,5752, girişte 0,5487 — soru sorulduğunda ölçü düşüyor. Bu sayıların hangi kayıttan okunduğu önemlidir: gizlenen tek etkileşim, o abonenin gösterilmiş bir kalemle kurduğu tek etkileşimdir ve gösterim düzeni ağırlıkla kataloğun üst ucunu sunmuştur. Taban tam olarak o üst ucu öneriyor.
Özet
- Soğuk başlangıç iki ayrı sorundur: kurgu dizeyde 80 abonenin hiç, 113 abonenin tek etkileşimi vardır ve tek etkileşim gizlenince 193 abone soğuk sayılır; kalem tarafında 464 etkileşimlik eğitim kümesinde 1 kalem hiç seçilmemiş, 8 kalem beşin altındadır.
- Popülerlik geri dönüşü 193/193 aboneyi ısıtır, hiçbir kalemi ısıtmaz ve hepsine aynı 5 kalemi verir; öznitelik köprüsü 1/1 kalemi ısıtır, hiçbir soğuk aboneyi ısıtmaz ve kalemi komşusunun yaygınlığı kadar taşır: 114 aboneye karşı 10 abone.
- Üç soruluk giriş 339 soru karşılığında 71 aboneyi ısıtır, 42 abone cevapsız kalır, kapsama 5’ten 13 kaleme çıkar; üçüncü soru her kalemi aynı katsayıyla çarptığı için sıralamayı hiç değiştirmez.
- Kayıttan okunan ilk beş isabeti tabanda 0,5752, girişte 0,5487’dir; bu kayıt yalnız gösterilmiş kalemlerdeki etkileşimlerden oluşur.
Sonraki Adım
Bu dersin son tablosu tuhaf bir şey söylüyor: soğuk aboneye sorular sorup önerileri onun kendi söylediği alana çevirmek, kayıttan okunan sayıyı düşürdü. İki açıklama var. Ya sorular işe yaramıyor, ya da ölçü yanlış yerden okunuyor — çünkü kayıttaki her etkileşim, kararı sistemin değil gösterim düzeninin verdiği bir anda doğdu ve gösterilmemiş bir kalemin etkileşimi kayıtta hiç görünmüyor. Sonraki ders sıralama ölçütlerini kurar: ilk k, kesme noktası ve konum indirimi. Sonra aynı sıralamayı iki kez ölçer — bir kez bu kayıt üzerinde, bir kez de sıralamanın kendisi neyin gösterileceğine karar verirken. İki sayı yan yana basılır.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.