İçeriğe geç

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
Bias Galaksisi: Position, Presentation, Popularity ve IPS Düzeltmesi
⚠️ 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ış#

BiasTanımEtkilediği Aşama
Position BiasListenin üstündeki item daha çok tıklanır (kalitesi aynı olsa bile)Click data toplama
Presentation BiasDaha güzel görsel, daha çok tıklama (kalitesi aynı olsa bile)Click data toplama
Popularity BiasPopüler item daha çok önerilir → daha çok popülerleşir (feedback loop)Sistem davranışı
Exposure BiasSistem sadece kendisinin önerdiği item'ı görüyor — diğerleri "yok" gibiTraining data
Selection BiasAktif 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ı)#

RankTıklama Olasılığı (relative)
11.00
20.55
30.40
40.30
50.23
60.18
70.15
80.13
90.11
100.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:
  1. Item gerçekten relevant (R = 1)
  2. Item gerçekten gözlemlendi (O = 1)
P(C = 1 | item gösterildi) = P(R = 1) · P(O = 1 | rank)
Burada
P(O = 1 | rank)
position bias — pozisyona bağlı examination probability.

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.
Position bias eğrisi — 1. sıra %100, 10. sıra %10 (kalite aynı varsayımıyla).
Position bias dramatik bir decay sergiler — ilk birkaç pozisyon tüm tıklamanın çoğunu alır.

IPS (Inverse Propensity Scoring) — Bias'ı Düzelt#

Position bias'ı düzeltmenin standart yolu: her observation'ı examination olasılığının tersi ile ağırlıkla.

Matematik#

Eğer naive loss:
L_naive = Σ (y_ui - f(u, i))²
Burada
y_ui
click (gözlemlendi). IPS düzeltmeli loss:

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:
  1. Click model'lerinden tahmin — Cascade Click Model, Position-based Model (PBM)
  2. 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 tahmini
import 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 test
np.random.seed(42)
N = 1000
preds = 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ı#

BiasNereden Geliyorİlk BelirtiPratik Çözüm
PositionUI listelemeHigh-rank item'ların inflate CTR'iIPS düzeltmesi, randomization deneyi
PresentationGörselAynı item farklı thumbnail farklı CTRThumbnail A/B + bandit
PopularityFeedback loopLong-tail görünmezPopularity penalty, reverse IPS
ExposureSistemin kendisiBir item asla önerilmiyorε-greedy, off-policy eval
SelectionVeri toplamaAktif user'lar dominantStratified 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