Bias Galaksisi: Position, Presentation, Popularity ve IPS Düzeltmesi
Recommender sistemlerinin 5 önemli bias'ı (position, presentation, popularity, exposure, selection), her birinin matematiksel tanımı, log data'da gözlemleme yolları, ve Inverse Propensity Scoring (IPS) düzeltmesinin türetimi + NumPy implementasyonu.
Şükrü Yusuf KAYA
30 dakikalık okuma
İleri⚠️ Bu ders zihninizi açacak
Recommender sistemlerinin en gizli, en zarar verici ve en az tartışılan sorunu bias'lardır. Bir model %99 doğru çalışabilir ama yanlış davranabilir — çünkü training data'sı bias'lı toplandı. Bu derste 5 ana bias'ı tanıyacaksın, her birinin matematiğini göreceksin, ve IPS (Inverse Propensity Scoring) ile düzeltme yapacaksın. Bu konu mid-level → senior eşiğinin en büyük belirleyicisi.
5 Ana Bias — Genel Bakış#
| Bias | Tanım | Etkilediği Aşama |
|---|---|---|
| Position Bias | Listenin üstündeki item daha çok tıklanır (kalitesi aynı olsa bile) | Click data toplama |
| Presentation Bias | Daha güzel görsel, daha çok tıklama (kalitesi aynı olsa bile) | Click data toplama |
| Popularity Bias | Popüler item daha çok önerilir → daha çok popülerleşir (feedback loop) | Sistem davranışı |
| Exposure Bias | Sistem sadece kendisinin önerdiği item'ı görüyor — diğerleri "yok" gibi | Training data |
| Selection Bias | Aktif kullanıcıların davranışı sessiz kullanıcılarınkinden çok farklı | Veri toplama |
Hepsi farklı yerden geliyor ama hepsinin ortak bir çözümü var: IPS.
1) Position Bias — "İlk Olan Tıklanır"#
Tanım#
Aynı kalitede iki item — biri 1. sırada, biri 10. sırada. 1. sıradaki 3-5 kat daha çok tıklanır. Bu content kalitesinden değil, pozisyondan geliyor.
Yayınlanmış Veri (Yahoo, Microsoft, Google çalışmaları)#
| Rank | Tıklama Olasılığı (relative) |
|---|---|
| 1 | 1.00 |
| 2 | 0.55 |
| 3 | 0.40 |
| 4 | 0.30 |
| 5 | 0.23 |
| 6 | 0.18 |
| 7 | 0.15 |
| 8 | 0.13 |
| 9 | 0.11 |
| 10 | 0.10 |
Kaynak: Joachims et al., "Accurately Interpreting Clickthrough Data as Implicit Feedback", SIGIR 2005. Yıllar boyunca tekrar gözlemlendi.
Matematiksel Tanım#
Bir click'in tetiklenmesi için iki olayın olması gerek:
- Item gerçekten relevant (R = 1)
- Item gerçekten gözlemlendi (O = 1)
P(C = 1 | item gösterildi) = P(R = 1) · P(O = 1 | rank)
Burada position bias — pozisyona bağlı examination probability.
P(O = 1 | rank)Sonuç#
Eğer P(O | rank) düzeltmezsen, modelin yanlış öğrenir: "1. sıradakiler iyi, 10. sıradakiler kötü" — halbuki rank seçimi modelin kendisi tarafından yapıldı. Bu kendi kuyruğunu yiyen yılan.
Neden İşe Yarar?#
Yüksek pozisyonlu item'ın examination olasılığı yüksek (örn. 1. sırada P(O)=1.0). Düşük pozisyon (örn. 10. sıra) düşük (P(O)=0.10).
Item A rank=1, tıklandı: Loss × 1/1.0 = Loss × 1.0 (normal) Item B rank=10, tıklandı: Loss × 1/0.1 = Loss × 10 (10x ağırlık!)
Yani 10. sırada tıklanan item, çok daha güçlü pozitif sinyal sayılır — çünkü o pozisyonda zaten az tıklanıyor, tıklanması özel.
Pratik Engel: P(O | rank) Nasıl Tahmin Edilir?#
Eye-tracking lab çalışmaları (Yahoo, Google) ile küçük örneklemde ölçülür. Endüstride iki pratik yöntem:
- Click model'lerinden tahmin — Cascade Click Model, Position-based Model (PBM)
- Randomization deneyi — bazı user'lara rastgele sıra göster, click oranlarını karşılaştır
python
# bias/ips.py — IPS düzeltmeli loss + Position-based propensity tahminiimport numpy as np # Yaygın kullanılan position bias eğrisi (Joachims et al. 2005'ten)POSITION_PROPENSITY = np.array([ 1.00, 0.55, 0.40, 0.30, 0.23, 0.18, 0.15, 0.13, 0.11, 0.10,] + [0.08] * 90) # 10'dan sonra hızla düz def ips_loss( preds: np.ndarray, # model çıktı, shape: (N,) labels: np.ndarray, # gerçek click, shape: (N,) positions: np.ndarray, # her sample'ın gösterildiği rank (1-indexli) clip_max: float = 10.0, # IPS weight'i clip et (varyans kontrolü)) -> float: """ IPS düzeltmeli MSE loss. Yüksek-rank (kuyrukta) tıklanan örnekler daha çok ağırlık alır. """ propensity = POSITION_PROPENSITY[positions - 1] ips_weights = np.clip(1.0 / propensity, a_min=None, a_max=clip_max) return np.mean(ips_weights * (preds - labels) ** 2) def estimate_propensity_from_swap(events: dict) -> np.ndarray: """ Randomization deneyinden propensity tahmin et. Bazı kullanıcılara rastgele sıra göster — onların click oranlarını pozisyona göre ortalama, propensity tahmini olur. events: {position: [n_clicks, n_impressions]} """ K = max(events.keys()) propensities = np.zeros(K) # Base rate (örn. 1. sıra) — normalize edici base_click_rate = events[1][0] / events[1][1] for pos in range(1, K + 1): n_click, n_impr = events[pos] if n_impr == 0: propensities[pos - 1] = 0.05 # fallback continue click_rate = n_click / n_impr propensities[pos - 1] = click_rate / base_click_rate return propensities # Smoke testnp.random.seed(42)N = 1000preds = np.random.uniform(0, 1, N)labels = np.random.binomial(1, 0.1, N)positions = np.random.randint(1, 11, N) naive_loss = np.mean((preds - labels) ** 2)ips_l = ips_loss(preds, labels, positions)print(f"Naive loss: {naive_loss:.4f}")print(f"IPS loss: {ips_l:.4f} (yüksek-rank tıklamalar daha ağır)") IPS loss + position bias propensity tahmini — pratik kod.
2) Presentation Bias — "Güzel Görünen Tıklanır"#
Tanım#
İki item — aynı kalitede, aynı pozisyonda. Ama biri yüksek-çözünürlüklü, parlak, hareketli thumbnail; diğeri donuk, düşük-çözünürlüklü. Birincisi 2-5 kat daha çok tıklanır.
Pratik Etki#
Netflix'in 2017'de "Artwork Personalization" sistemini eklemesinden sonra CTR +%30 arttı. Hala aynı içeriklerdi — sadece presentation değişti. Bu presentation bias'ın gücü.
Düzeltme Stratejisi#
- Eğitim sırasında: Aynı item'ın farklı varyantlarını comparable şekilde göster (A/B testing thumbnail).
- Inference sırasında: Modelin output'unu thumbnail kalitesine göre düzeltmek zor — bunun yerine A/B test ile thumbnail seçimini optimize et.
- Multi-armed bandit yaklaşımı: Her thumbnail bir "arm" — Thompson sampling ile en iyisini bul.
3) Popularity Bias — Feedback Loop'un Kötü Şekli#
Mekanizma#
Item X popüler → model X'i daha çok önerir → daha çok tıklanır → daha popüler ↓ Yeni döngünün başı
Bu kendi kendini güçlendiren feedback loop. Sonucu:
- Long-tail item'lar görünmez olur — keşfedilemez.
- Short-term metrics (CTR) iyileşir — short-term doğru görünür.
- Long-term diversity ve user satisfaction düşer — kullanıcı "hep aynı şeyleri görüyorum" der.
Nasıl Görülür?#
Eğer dataset'te ortalama recommendation'ın popularity'si zaman içinde artıyorsa — sistem popularity bias'a sahip.
import polars as pl # Aylık recommendation'ların ortalama log_popularity'si events = ... # log dataframe with [user, item, rec_position, timestamp] item_popularity = ( events.group_by("item_id") .agg(pl.count().alias("global_pop")) ) monthly_avg_pop = ( events.join(item_popularity, on="item_id") .with_columns(pl.col("timestamp").dt.month_start().alias("month")) .group_by("month") .agg(pl.col("global_pop").mean().log().alias("avg_log_pop")) ) # Eğer bu zaman içinde artıyorsa: popularity bias var
Düzeltme#
1. Popularity Penalty (Re-ranking aşamasında)
# Modelin skoru - α * log(popularity) adjusted_score = model_score - alpha * np.log(item_popularity + 1)
2. Reverse Propensity Weighting
Training sırasında popüler item'lara düşük ağırlık, az popülerlere yüksek:
ips_weight = 1 / (popularity ^ beta) # beta ∈ [0.5, 1.0]
3. Diversification Layer
Modül 16'da göreceğiz — MMR, DPP gibi tekniklerle final listede çeşitlilik zorla.
4) Exposure Bias — "Görmediğini Bilemezsin"#
Tanım#
Sistem sadece kendisinin daha önce önerdiği item'lar hakkında veriye sahip. Önermediği item'ları kullanıcı görmediği için click datası yok — sanki o item'lar dünya'da yokmuş gibi.
Sonuç#
Item Z hiç önerilmemiş. → 0 click, 0 view, 0 satın alma. → Model "Item Z kötü" çıkarımı yapar (negative sample). → Item Z bir daha önerilmez.
Bu döngünün kapanması. Item Z asla değerlendirilemez.
Çözüm Stratejileri#
1. Exploration / Random Sampling
Her gün küçük yüzde trafiği rastgele dağıt. Bu sayede tüm item'lar için minimum sinyal toplanır.
2. ε-greedy at Serving Time
if random.random() < epsilon: # %5 olasılıkla random öneri return random_items(K) else: return model_top_k(K)
3. Counterfactual Reasoning (Off-Policy Evaluation)
Daha gelişmiş: gözlemlenmeyen item'ların "ne olurdu" değerini tahmin et. Bu off-policy evaluation (Modül 19'da derinlemesine).
5) Selection Bias — Sessiz Kullanıcılar Görünmez#
Tanım#
Dataset'inde sadece aktif kullanıcıların davranışı var — pasif kullanıcılar log yapmıyor. Modelin "tüm kullanıcılar bu aktivite seviyesinde" varsayımı yanlış.
Gerçek Örnek: MovieLens#
ML datasetlerinde her kullanıcının minimum 20 rating'i var (filter uygulanmış). Bu sentetik bir koşul — gerçek kullanıcıların büyük çoğunluğu hiç rating vermez. Yani MovieLens üzerinde eğitilen bir model "rating veren kullanıcılar nasıl davranır" sorusuna cevap verir, "tüm kullanıcılar nasıl davranır" değil.
Production'da#
Aktif kullanıcıların tutumu pasiflerinkinden farklıdır:
- Aktif: çeşitli kategoriler, derin browse, niş ilgi alanları
- Pasif: top-tier popular ürünler, yüzeysel browse
Eğer sadece aktiflerden öğrenirsen, pasiflere yanlış öneri yaparsın.
Düzeltme#
- Stratified sampling: Test set'inde aktif/pasif user oranını real-world'e yakın tut.
- Two-population modeling: Aktif ve pasif user'ları ayrı sub-model'lerle modelle.
- Calibration: Modelin global activity-distribution tahminini gerçek dağılımla eşitle.
Bias Galaksisi — Özet Tablo + Çözüm Haritası#
| Bias | Nereden Geliyor | İlk Belirti | Pratik Çözüm |
|---|---|---|---|
| Position | UI listeleme | High-rank item'ların inflate CTR'i | IPS düzeltmesi, randomization deneyi |
| Presentation | Görsel | Aynı item farklı thumbnail farklı CTR | Thumbnail A/B + bandit |
| Popularity | Feedback loop | Long-tail görünmez | Popularity penalty, reverse IPS |
| Exposure | Sistemin kendisi | Bir item asla önerilmiyor | ε-greedy, off-policy eval |
| Selection | Veri toplama | Aktif user'lar dominant | Stratified sampling, calibration |
Bir Cümlede#
"Eğer modeline veriyi olduğu gibi besliyorsan, modelin sadece mevcut sistemin önyargılarını öğreniyor. Bias düzeltmesi yapmadan, modelin kendi geçmişini taklit eden bir oracle olur."
📖 Gerçek hikaye — bir startup'tan
Bir Türk e-ticaret startup'ına consulting verirken durum şuydu: 'recommender modeli A/B test'te CTR'i %8 arttırdı.' Online metrik harika. Ama 4 ay sonra: 'kullanıcı satın alma çeşitliliği %30 düştü.' Long-tail satıcılar şikayet etmeye başladı. Çünkü model popularity loop'a girdi. Çözüm: re-ranking layer'da popularity penalty + her gün %5 random exploration. CTR %6'ya geriledi ama diversity geri geldi ve LTV %15 arttı. Doğru metric'i ölçmediğinde başın belaya girer.
Sıradakİ Ders#
Bir sonraki derste (2.4) — modülün son dersi: GDPR, KVKK ve "Unutulma Hakkı" recommender bağlamında. Avrupa AI Act ve Türkiye'nin 2026 itibariyle güncellenen KVKK rehberleri. Sıkıcı görünüyor ama 'bir gün canınıza okuyabilir' — özellikle Türkiye Big Tech çalışanı veya yurt dışına remote için.
Sık Sorulan Sorular
İki pratik yol: (1) Randomization deneyi — küçük bir kullanıcı grubuna rastgele sıra göster (örn. %1 trafik), kontrol grubuyla karşılaştır. Position-bazlı CTR farkı = propensity tahmini. (2) Click model'leri — Cascade Click Model (CCM) veya Position-based Model (PBM) ile log'tan estimate. Joachims et al. 2017 paper'ı detaylı.
Yorumlar & Soru-Cevap
(0)Yorum yazmak için giriş yap.
Yorumlar yükleniyor...
İlgili İçerikler
Modül 0: Kurs Çerçevesi ve Atölye Kurulumu
Öneri Sistemleri Neden Bu Kadar Önemli? Bir Disiplinin Doğuşu, Bugünü ve Yarını
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu
Recommender Engineer Kimdir? Yetkinlik Atlası ve Junior → Staff Kariyer Haritası
Öğrenmeye BaşlaModül 0: Kurs Çerçevesi ve Atölye Kurulumu