Measurement Problems #2: Sorting Products
Online eğitim platformlarında ya da e-ticaret sitelerinde gördüğümüz sıralamalar yalnızca kullanıcı puanlarına dayanmaz. Benzer şekilde…
Measurement Problems #2: Sorting Products
Online eğitim platformlarında ya da e-ticaret sitelerinde gördüğümüz sıralamalar yalnızca kullanıcı puanlarına dayanmaz. Benzer şekilde, bir iş ilanına başvuran adaylar da sadece diploma notlarına göre değerlendirilmez. Peki, birden fazla metriği kullanarak daha adil, akılcı ve kullanıcı/kurum odaklı sıralama nasıl yapılır?
Bu yazıda, hem ürün hem de insan değerlendirme süreçlerinde kullanabileceğimiz Bayesian Average Rating, Weighted Rating, Hybrid Score ve Ağırlıklı Karar Modelleri gibi yaklaşımlara değineceğim. Ayrıca Python ile örnek uygulamalara yer vererek bu teoriyi pratiğe dökeceğim.

#E-ticaret sitelerinde bir ürünün sıralamadaki yeri genellikle 3 metrikle şekillenir:
🔹Ortalama kullanıcı puanı (rating)
🔹Toplam yorum sayısı
🔹Satın alma verisi
⚠️Ancak yalnızca ortalama puana göre sıralama yapmak yanıltıcıdır. Örneğin 5 yıldız almış ama sadece 2 kişi tarafından değerlendirilmiş bir ürün, binlerce değerlendirme almış 4.6 puanlık bir ürünün önüne geçmemelidir.
Burada devreye şu teknikler girer:
✅ Bayesian Average Rating (BAR)
✅ Weighted Rating
✅ Hybrid Score
#Bir işe alım sürecinde genellikle şu kriterler öne çıkar:
🔹Mezuniyet puanı
🔹Yabancı dil puanı
🔹Mülakat performansı
Ancak tüm bu kriterlerin ağırlığı eşit değildir. Mülakat, adayın role olan uygunluğunu doğrudan gösterdiği için daha fazla ağırlık verilmelidir.
🎯 Önerilen Ağırlıklar:
🔹%55 Mülakat Puanı
🔹%25 Mezuniyet Puanı
🔹%20 Yabancı Dil Puanı
Bu ağırlıklarla, her aday için bileşik bir skor oluşturulur ve adaylar bu skora göre sıralanır. Bu yöntem, sadece “izlenim” e değil, veri temelli bir yapıya dayanır. Böylece hem daha adil hem de daha tutarlı işe alım kararları verilebilir.
#Dışsal Bilgi mi, İçsel Veri mi? Doğru Sıralamanın Temelleri
🔎Google’da bir şey aradığınızda ya da Netflix size film önerdiğinde sistem, sizin verdiğiniz bilgiye göre çalışır. Yani anahtar kelimeniz ya da izleme geçmişiniz üzerinden içeriklerle eşleşme yapılır. Bu tür sistemler genellikle TF-IDF gibi tekniklerle, dışarıdan gelen bu bilgilere tepki verir. Buna dışsal bilgiye göre sıralama denir.
Ancak bir ürün ya da aday sıralanacaksa, işler değişir. Çünkü kullanıcıdan gelen bir “arama” yoktur. Bu durumda sıralama, içeriğin kendi verilerine göre yapılır. Örneğin bir ürünün puanı, yorum sayısı, satış adedi veya bir adayın mezuniyet notu, yabancı dil seviyesi, mülakat sonucu gibi. Yani burada içsel bilgiye göre sıralama yapılır. Bu nedenle metin benzerliği değil, skor hesaplamalarına dayalı modeller (örneğin Bayesian Rating, Weighted Average) kullanmak gerekir.
📌İlk senaryomuzda elimizde bir kurs verisi olsun.
#Gerekli kütüphaneler import ediliyor
import pandas as pd
import math
import scipy.stats as st
from sklearn.preprocessing import MinMaxScaler
#Konsolda daha okunabilir veri gösterimi için ayarlamalar
pd.set_option('display.max_columns', None) #Tüm sütunları göster
pd.set_option('display.max_rows', None) #Tüm satırları göster
pd.set_option('display.expand_frame_repr', False) #Geniş verilerin alt satıra taşmasını engelle
pd.set_option('display.float_format', lambda x: '%.5f' % x) #Sayıları virgülden sonra 5 basamaklı göster
#CSV dosyasından veri seti yükleniyor
df = pd.read_csv("datasets/product_sorting.csv")
#Veri setinin boyutu (satır, sütun) ekrana yazdırılıyor
print(df.shape)
#İlk 10 satır görüntüleniyor
df.head(10)
Kurs verisinin ilk 10 satırı aşağıdaki gibi görünmektedir:

#instructor_name : eğitmenler
#purchase_count : satın alma sayısı
#rating: kursun ortalama puanı
#comment_count: kursun yorum sayısı
#5_point, 4_point,3_point, ... : yorumlar neticesinde verilen puanlar
#Sorting by Rating (Rating’ lere Göre Sıralama)
df.sort_values("rating", ascending=False).head(10)

Bazı kurslar çok fazla satın alındığı ve çok yorum aldığı halde, sadece puanlarına bakarak sıralandıklarında geride kalabiliyorlar. Mesela; 5 yıldız almış ama sadece 3 kişi tarafından oy verilmiş bir kurs ile 4.5 yıldız almış ama 10.000 kişi tarafından değerlendirilmiş bir kurs arasında seçim yapacak olsak, çoğumuz ikinci kursu tercih ederiz.
Bunun sebebi şudur: Yorum sayısı ve satın alma sayısı, kursun ne kadar güvenilir ve popüler olduğunu gösterir. Buna sosyal ispat denir.
Bu yüzden sıralama yaparken sadece puana bakmamalıyız. Hem puanı, hem yorum sayısını hem de satın alma sayısını birlikte değerlendirmeliyiz. Bu sayede kullanıcıya daha gerçekçi ve adil bir sıralama sunabiliriz.
#Sorting by Comment Count or Purchase Count (Yorum ya da Satın Alma Sayısına Göre Sıralama)

Satın alma sayısına göre sıralama

Yorum sayısına göre sıralama
Bir kursun çok satılmış olması onun mutlaka kaliteli olduğunu göstermez; çünkü bazı kurslar ücretsiz olarak da dağıtılmış olabilir. Sadece puana (rating) göre sıralama yapmak da yeterli değildir, çünkü az kişi tarafından oy almış yüksek puanlı kurslar yanıltıcı olabilir. Bu yüzden puan, yorum sayısı ve satın alma sayısını birlikte değerlendirmek gerekir. Bu üç veriyi ortak bir ölçekte standartlaştırıp, tek bir skor haline getirerek kursları buna göre sıralamak en doğru ve adil yöntem olacaktır.
#Sorting by Rating,Comment and Purchase (Satın Alma Sayısı, Yorum Sayısı ve Rating’ e Göre Sıralama)
Kursları puan, yorum sayısı ve satın alma sayısına göre sıralamak istiyorsak, bu üç veriyi doğrudan çarpamayız çünkü hepsi farklı büyüklükte. Satın alma sayısı çok yüksek olduğu için, çarpınca puanı ve yorum sayısını ezebilir. Bu yüzden önce hepsini aynı ölçeğe getirmeliyiz. En mantıklı yol, hepsini 1 ile 5 arasında bir aralığa yani puan (rating) ölçeğine dönüştürmektir. Böylece her veri eşit şekilde değerlendirilir ve daha adil bir sıralama yapılabilir.
#'purchase_count' değerlerini 1-5 aralığına ölçeklendiriyoruz (Min-Max Normalizasyon)
df["purchase_count_scaled"] = MinMaxScaler(feature_range=(1, 5)). \
fit(df[["purchase_count"]]). \
transform(df[["purchase_count"]])
#İlk birkaç satırı görüntüleyerek dönüşümün etkisini kontrol ediyoruz
df.head()
#Tüm sayısal sütunların özet istatistiklerini inceliyoruz (standart sapma, ortalama, min, max vs.)
df.describe().T
# 'comment_count' (yorum sayısı) değerlerini de 1-5 aralığına ölçeklendiriyoruz
df["commment_count_scaled"] = MinMaxScaler(feature_range=(1, 5)). \
fit(df[["commment_count"]]). \
transform(df[["commment_count"]])
# Ağırlıklı skor hesaplama formülü (tek seferlik):
# Yorum sayısı %32, satın alma sayısı %26, puan %42 ağırlıkla değerlendiriliyor
(df["commment_count_scaled"] * 32 / 100 +
df["purchase_count_scaled"] * 26 / 100 +
df["rating"] * 42 / 100)
# Yukarıdaki hesaplamayı tekrar kullanmak yerine bir fonksiyon haline getiriyoruz
def weighted_sorting_score(dataframe, w1=32, w2=26, w3=42):
return (dataframe["commment_count_scaled"] * w1 / 100 +
dataframe["purchase_count_scaled"] * w2 / 100 +
dataframe["rating"] * w3 / 100)
# Fonksiyonu kullanarak yeni bir sütun oluşturuyoruz: 'weighted_sorting_score'
# Bu, her kursun toplam puanını (3 faktöre göre) gösteren bileşik skor
df["weighted_sorting_score"] = weighted_sorting_score(df)
#Purchase_count, comment_count ve rating'i bir arada değerlendirdiğimiz weighted_sorting_score'a göre azalan şekilde sıralama yaptık
df.sort_values("weighted_sorting_score", ascending=False).head(20)
#Kursun isminde "Veri Bilimi" içerenleri ekrana getir
df[df["course_name"].str.contains("Veri Bilimi")].sort_values("weighted_sorting_score", ascending=False).head(20)

df.sort_values(“weighted_sorting_score”, ascending=False).head(20) satırının çalışması
![df[df[“course_name”].str.contains(“Veri Bilimi”)].sort_values(“weighted_sorting_score”, ascending=False).head(20) satırının çalışması](https://miro.medium.com/v2/resize:fit:1400/1*zh4Cc3GM3A75mQaSjlF3LA.png)
df[df[“course_name”].str.contains(“Veri Bilimi”)].sort_values(“weighted_sorting_score”, ascending=False).head(20) satırının çalışması
#Bayesian Average Rating Score (Bayes Ortalama Derecelendirme Puanı)
Kurslara verilen yıldız puanlarının (1 yıldızdan 5 yıldıza kadar) dağılımı elimizde mevcut. Bu dağılımları kullanarak, sadece basit ortalama yerine olasılıksal ve daha güvenilir bir ortalama hesaplamak mümkündür. Böylece, geçmiş kullanıcı davranışlarına dayanarak daha dengeli bir puanlama elde ederiz.
Burada n adlı bir yapı kullanıyoruz; bu yapı her yıldız seviyesi için kaç kişinin oy verdiğini belirtir. Örneğin:
n[0]→ 1 yıldız sayısın[1]→ 2 yıldız sayısı
…
n[4]→ 5 yıldız sayısı
Bu bilgilerle, her kursun sadece ortalama puanına değil, puanların nasıl dağıldığına göre daha sağlıklı bir sıralama yapabiliriz.
#Bayesian Average Rating hesaplayan fonksiyon
# n: her bir puan seviyesindeki (1-5) oy sayılarının bulunduğu seri (örneğin [100, 200, 300, 250, 150])
# confidence: güven düzeyi (varsayılan %95)
def bayesian_average_rating(n, confidence=0.95):
#Eğer hiç oy yoksa, skor 0 kabul edilir
if sum(n) == 0:
return 0
#K: farklı puan seviyelerinin sayısı (örneğin 5 yıldız için 5)
K = len(n)
#z: normal dağılımdan güven düzeyine göre z değeri (örn. %95 için ≈ 1.96)
z = st.norm.ppf(1 - (1 - confidence) / 2)
#N: toplam oy sayısı
N = sum(n)
#Bayesian ortalama hesaplamasında kullanılacak iki parça tanımlanıyor
first_part = 0.0
second_part = 0.0
#Her puan seviyesi için döngüye giriyoruz (örneğin 1-5 yıldız arası)
for k, n_k in enumerate(n):
#k + 1: gerçek puan değeri (index 0'dan başladığı için)
#(n.iloc[k] + 1): Laplace smoothing (her sınıfa 1 oy eklenerek sıfır bölme riskinden kaçınılır)
first_part += (k + 1) * (n.iloc[k] + 1) / (N + K)
second_part += (k + 1) * (k + 1) * (n.iloc[k] + 1) / (N + K)
#Bayesian ortalama puan hesaplama formülü
#z * std sapma ile belirsizlik azaltılıyor
score = first_part - z * math.sqrt((second_part - first_part * first_part) / (N + K + 1))
return score
#Her satır (yani her kurs) için 1-5 yıldız oylarının bulunduğu sütunları alarak
#bayesian_average_rating fonksiyonu ile güvenilir bir puan (bar_score) hesaplıyoruz.
#axis=1 dememizin nedeni, apply fonksiyonunun her sütunda çalışmasını istememizdir.
df["bar_score"] = df.apply(lambda x: bayesian_average_rating(x[["1_point",
"2_point",
"3_point",
"4_point",
"5_point"]]) , axis=1)
#İlk birkaç satırı kontrol ederek yeni bar_score sütununun eklendiğinden emin oluruz
df.head()
#Daha önce hesapladığımız ağırlıklı sıralama skoruna göre kursları yüksekten düşüğe sıralıyoruz
df.sort_values("weighted_sorting_score", ascending=False).head(20)
#Bayesian ortalama skoruna (bar_score) göre en güvenilir kursları sıralıyoruz
df.sort_values("bar_score", ascending=False).head(20)
#Belirli satır indekslerine (örneğin index 5 ve index 1) sahip kursları filtreliyoruz.
#course_name sütununa göre değil, doğrudan DataFrame’in satır indekslerini kullanıyoruz.
#Ardından, bu iki kursu bar_score değerine göre yüksekten düşüğe sıralıyoruz.
df[df["course_name"].index.isin([5, 1])].sort_values("bar_score", ascending=False)

bar_score ekrana geldi
![df[df[“course_name”].index.isin([5, 1])].sort_values(“bar_score”, ascending=False) satırının çalışması](https://miro.medium.com/v2/resize:fit:1400/1*83n-YRBBMQMaLk5EbVv7qA.png)
df[df[“course_name”].index.isin([5, 1])].sort_values(“bar_score”, ascending=False) satırının çalışması
Sadece rating, yorum ya da satın alma sayısı tek başına yeterli değil. Bu yüzden üçünü birleştirerek ağırlıklı bir skor oluşturduk. Sonrasında, puan dağılımını da dikkate alan Bayesian ortalama (bar_score) ile daha güvenilir bir değerlendirme yaptık. Şimdi ise bu iki skoru birleştirerek daha dengeli ve adil bir sıralama elde edeceğiz.
#Hybrid Sorting
#wss (weighted_sorting_score): Yorum sayısı, satın alma ve rating üzerinden ağırlıklı puan
#bar (bayesian_average_rating): Yorumların puan dağılımına göre hesaplanan güvenilir puan
#Bu fonksiyon, hem bar_score'u hem de wss_score'u belli ağırlıklarla birleştirerek
#hibrit (karma) bir sıralama skoru üretir.
def hybrid_sorting_score(dataframe, bar_w=60, wss_w=40):
#Her satır (kurs) için bar_score hesaplanıyor
bar_score = dataframe.apply(lambda x: bayesian_average_rating(x[["1_point",
"2_point",
"3_point",
"4_point",
"5_point"]]), axis=1)
#Daha önce hesapladığımız weighted_sorting_score fonksiyonu çağrılıyor
wss_score = weighted_sorting_score(dataframe)
#Belirtilen ağırlıklar oranında bar_score ve wss_score birleştiriliyor
return bar_score * bar_w / 100 + wss_score * wss_w / 100
#Hibrit skorları DataFrame'e yeni bir sütun olarak ekliyoruz
df["hybrid_sorting_score"] = hybrid_sorting_score(df)
#Hibrit skora göre en yüksek puan alan 20 kursu sıralayıp görüntülüyoruz
df.sort_values("hybrid_sorting_score", ascending=False).head(20)
#Kurs ismi içinde "Veri Bilimi" geçenleri filtreliyoruz,
#bu kursları hibrit skora göre sıralayıp en iyi 20 tanesini listeliyoruz
df[df["course_name"].str.contains("Veri Bilimi")].sort_values("hybrid_sorting_score", ascending=False).head(20)

hybrid_sorting_score ekrana gelmiş oldu.

1-Kurs ismi içinde “Veri Bilimi” geçenleri filtreliyoruz

2-Kurs ismi içinde “Veri Bilimi” geçenleri filtreliyoruz
🎯Sonuç
Kısacası, bir içeriği sadece aldığı puana göre değil; puan dağılımı, yorum sayısı ve satın alma gibi sosyal ispat unsurlarını da dikkate alarak değerlendirmek, hem kullanıcı deneyimini iyileştirir hem de daha adil ve güvenilir bir sıralama sistemi oluşturur. Bu yaklaşım, içerik öneri sistemlerinde sezgisel değil, veriye dayalı kararların ne kadar kritik olduğunu bir kez daha gösteriyor.
👉Bir sonraki yazımda, yorumların sıralanması yöntemleri ve teknikleri, yani “sorting reviews” konusunu detaylıca inceleyeceğim. Takipte kalın!😊
메타데이터
- post_id
- e34d74981d8d
- slug
- measurement-problems-2-sorting-products-e34d74981d8d
- url
- https://medium.com/@dilaanbb/measurement-problems-2-sorting-products-e34d74981d8d
- canonical_url
- https://medium.com/@dilaanbb/measurement-problems-2-sorting-products-e34d74981d8d
- author_url
- https://medium.com/@dilaanbb
- status
- ok
- fetched_at
- 2026-06-26 03:39:16