Measurement Problems(Product Rating&Sorting)
Merhabalar,e-ticaret sitesinde alışveriş yaparken aldığınız ürünü sizlere satın aldıran dürtünün ne olduğunu hiç düşündünüz mü?
Yapılan bilimsel araştırmalara göre burada ki en büyük dürtünün “Social Proof”(‘The Wisdom of Crowds’) olduğu yönündedir.
Peki istatistiksel ve veri bilimine bakan yönü ile bu ürünlerin satın alınmasını nasıl ölçeklendirebiliriz?
- Ürün puanlarının alınması(product rating)
- Ürün sıralanması(product sorting)
- Yorumların sıralanması(sorting reviews)
- Ürün detay sayfalarında ki kullanıcı yorumlarının sıralanması(Binary Intersection)
- Sayfa,süreç ve etkileşim alanlarının tasarımları(A/B Testing)
Case:Kullanıcı ve zaman ağırlıklı Udemy kurs puanı hesaplama
#gerekli kütüphaneleri import edelim.
import pandas as pd
import math
import scipy.stats as st
from sklearn.preprocessing import MinMaxScaler
pd.set_option('display.max_columns', None)
pd.set_option('display.max_rows', None)
pd.set_option('display.width', 500)
pd.set_option('display.expand_frame_repr', False)
pd.set_option('display.float_format', lambda x: '%.5f' % x)
Örnek bir Udemy kurs verisi inceleyelim…
# (50+ Saat) Python A-Z™: Veri Bilimi ve Machine Learning
# Puan: 4.8 (4.764925)
# Toplam Puan: 4611
# Puan Yüzdeleri: 75, 20, 4, 1, <1
# Yaklaşık Sayısal Karşılıkları: 3458, 922, 184, 46, 6
Asıl verimiz olan “course.reviews.csv” veri setini çağıralım
#verimizi çağıralım.
df = pd.read_csv(“C:/Users/Lenovo/OneDrive/Masaüstü/course_reviews.csv”)
df.head()
# rating frekansı
df["Rating"].value_counts()# sorulan soru frekansı
df["Questions Asked"].value_counts()# sorulan soru kırılımında verilen puan
df.groupby("Questions Asked").agg({"Questions Asked": "count",
"Rating": "mean"})
Questions Asked Rating
Questions Asked
0.00000 3867 4.76519
#Burada ki output çıktısından yorumlayacağımız şey,3867 hiç soru sormayan kullanıcın ortalama puan 4.76# Time-Based Weighted Average:
df['Timestamp'] = pd.to_datetime(df['Timestamp']) 'Timestamp' değişkenini datetime cinsinden bir dataframe olarak kayıt edelim.
current_date = pd.to_datetime('2021-02-10 0:0:0') incelediğimiz veri setinde ki son gün olarak aldığımız tarih-saati current_date olarak atadık.
df["days"] = (current_date - df['Timestamp']).dt.days
#'days' değşkeni ile kaç gün önce yorum yapıldığı bilgisine ulaşıyoruz.df.loc[df["days"] <= 30, "Rating"].mean() * 28 / 100 + \ #30 gün veya daha az sürede oy vermiş kullanıcıların oy ortalamasını %28'i alınsın...
df.loc[(df["days"] > 30) & (df["days"] <= 90), "Rating"].mean() * 26 / 100 + \ #30 günden daha eski oy vermiş kullanıclarınn oy ortalamsının %26'sı alınsın...
df.loc[(df["days"] > 90) & (df["days"] <= 180), "Rating"].mean() * 24 / 100 + \ # 90 günden fazla 180 günden az sürede oy vermiş kullanıcıların oy ortalamasının %24'ü alınsın..
df.loc[(df["days"] > 180), "Rating"].mean() * 22 / 100
#180 günden fazla sürede oy vermiş kullanıcıların oy ortalamasının %22'si alınsın...Ve bu ağırlık değerlerini w1=28,w2=26,w3=24,w4=22 olarak weighted_average adında fonskiyona tanımlayalım.def time_based_weighted_average(dataframe, w1=28, w2=26, w3=24, w4=22):
return dataframe.loc[df["days"] <= 30, "Rating"].mean() * w1 / 100 + \
dataframe.loc[(dataframe["days"] > 30) & (dataframe["days"] <= 90), "Rating"].mean() * w2 / 100 + \
dataframe.loc[(dataframe["days"] > 90) & (dataframe["days"] <= 180), "Rating"].mean() * w3 / 100 + \
dataframe.loc[(dataframe["days"] > 180), "Rating"].mean() * w4 / 100
tanımladığımız fonskiyonumuzu çağıralım...
time_based_weighted_average(df)# User Kalitesine Göre Ağırlıklı Ortalama:
df.loc[df["Progress"] <= 10, "Rating"].mean() * 22 / 100 + \
df.loc[(df["Progress"] > 10) & (df["Progress"] <= 45), "Rating"].mean() * 24 / 100 + \
df.loc[(df["Progress"] > 45) & (df["Progress"] <= 75), "Rating"].mean() * 26 / 100 + \
df.loc[(df["Progress"] > 75), "Rating"].mean() * 28 / 100#kullanıcı temelli ağırlık ortalamasını fonksiyonlaştıralım.def user_based_weighted_average(dataframe, w1=22, w2=24, w3=26, w4=28):
return dataframe.loc[dataframe["Progress"] <= 10, "Rating"].mean() * w1 / 100 + \
dataframe.loc[(dataframe["Progress"] > 10) & (dataframe["Progress"] <= 45), "Rating"].mean() * w2 / 100 + \
dataframe.loc[(dataframe["Progress"] > 45) & (dataframe["Progress"] <= 75), "Rating"].mean() * w3 / 100 + \
dataframe.loc[(dataframe["Progress"] > 75), "Rating"].mean() * w4 / 100tanımladığımız fonksiyonu çağıralım..
user_based_weighted_average(df)# Weighted Rating:Kurslara verilen ağırlık oyları fonskiyonlaştıralım.
def course_weighted_rating(dataframe, time_w=50, user_w=50):
return time_based_weighted_average(dataframe) * time_w / 100 + user_based_weighted_average(dataframe) * user_w / 100
#time_based,user_based argümanlarını %50 olacak şekilde tanımladık.tanımladığımız fonksiyonumuzu çağıralım.
course_weighted_rating(df)# Sorting Products: product_sorting.csv veri setimizi çağırıp ilk 5 gözlemi inceleyelim.
df = pd.read_csv("C:/Users/Lenovo/OneDrive/Masaüstü/product_sorting.csv")
df.head()
# Sorting by Rating: oylama sayısına göre sort yapalım.
df.sort_values("rating", ascending=False).head(20)#NOT!!!! Sadece oylamaya göre kursu değerlendirmek yanlılığa sebep olacaktır,dolayısıyla toplam satılma sayısı ve yorum sayısını da sıralamak gerekir.df.sort_values("purchase_count", ascending=False).head(20)
df.sort_values("commment_count", ascending=False).head(20)#Peki hem oy hem satılma,hem de yorum sayısına göre bir sıralama yapmak istediğimizi düşünelim...
Standartlaştıralım.scale iledf["purchase_count_scaled"] = MinMaxScaler(feature_range=(1, 5)). \
fit(df[["purchase_count"]]). \
transform(df[["purchase_count"]])
df["commment_count_scaled"] = MinMaxScaler(feature_range=(1, 5)). \
fit(df[["commment_count"]]). \
transform(df[["commment_count"]])
#Standartlaştırmadan sonra ağırlık hesabı yaptık.En fazla ağırlığı rating aldı çünkü standartlaştırma rating'e göre yapıldı.(df["commment_count_scaled"] * 32 / 100 +
df["purchase_count_scaled"] * 26 / 100 +
df["rating"] * 42 / 100)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)
#weighted_sorting_score değişkenini dataframe olarak atadık.df["weighted_sorting_score"] = weighted_sorting_score(df)
df.sort_values("weighted_sorting_score", ascending=False).head(20)
#atanan weighted_sorting_score dataframe göre sıralama yapıldı.Bayesian Average Rating Score:
# Sorting Products with 5 Star Rated
# Sorting Products According to Distribution of 5 Star Rating
def bayesian_average_rating(n, confidence=0.95):
"""
N yıldızlı puan sisteminde wilson lower bound score'u hesaplamak için kullanılan fonksiyon.
Parameters
----------
n: list or df
puanların frekanslarını tutar.
Örnek: [2, 40, 56, 12, 90] 2 tane 1 puan, 40 tane 2 puan, ... , 90 tane 5 puan.
confidence: float
güven aralığı
Returns
-------
BAR score: float
BAR ya da WLB skorları
"""
N yıldızlı puan sisteminde wilson lower bound score'u hesaplamak için kullanılan fonksiyon.
Parameters
----------
n: list or df
puanların frekanslarını tutar.
Örnek: [2, 40, 56, 12, 90] 2 tane 1 puan, 40 tane 2 puan, ... , 90 tane 5 puan.
confidence: float
güven aralığı
Returns
-------
BAR score: float
BAR ya da WLB skorları
"""
# rating'lerin toplamı sıfır ise sıfır dön.
if sum(n) == 0:
return 0
# eşsiz yıldız sayısı. 5 yıldızdan da puan varsa 5 olacaktır.
K = len(n)
# 0.95'e göre z skoru.
z = st.norm.ppf(1 - (1 - confidence) / 2)
# toplam rating sayısı.
N = sum(n)
first_part = 0.0
second_part = 0.0# formülasyondaki hesapları gerçekleştir.
for k, n_k in enumerate(n):
first_part += (k + 1) * (n[k] + 1) / (N + K)
second_part += (k + 1) * (k + 1) * (n[k] + 1) / (N + K)
score = first_part - z * math.sqrt((second_part - first_part * first_part) / (N + K + 1))
return score
#Fancy Index ile bar_sorting_score fonksiyonu tanımlayalım.
df["bar_sorting_score"] = df.apply(lambda x: bayesian_average_rating(x[["1_point",
"2_point",
"3_point",
"4_point",
"5_point"]]), axis=1)--- sütunlara uygulandıdf.sort_values("bar_sorting_score", ascending=False).head(20)Hybrid Sorting: BAR Score + Diğer Faktorler:def hybrid_sorting_score(dataframe, bar_w=60, wss_w=40):
bar_score = dataframe.apply(lambda x: bayesian_average_rating(x[["1_point",
"2_point",
"3_point",
"4_point",
"5_point"]]), axis=1)wss_score = weighted_sorting_score(df)
return bar_score*bar_w/100 + wss_score*wss_w/100#hybrid_sorting_score df olarak atayalım..
df["hybrid_sorting_score"] = hybrid_sorting_score(df)df.sort_values("hybrid_sorting_score", ascending=False).head(20)#course_name olanlarında içerisinde veri bilimi geçen ilk 20 gözlemi getir.
df[df["course_name"].str.contains("Veri Bilimi")].sort_values("hybrid_sorting_score", ascending=False).head(20)