Cosine Similarity, Rating eşiği ve matematiksel formüllerle Recommender System (Öneri Sistemi) Uygulaması Geliştirme

Emre Havan
21 min readDec 5, 2019
Kaynak

Merhabalar,

Bu yazıda, Python, Cosine Similarity ve diğer matematiksel fonksiyonlar kullanarak öneri uygulaması (Recommender System, Recommender Engine) geliştireceğiz. Bu uygulama yüksek lisans bitirme projemde geliştirdiğim uygulamanın bir kısmını içeriyor olacak. Eğer dilerseniz bitirme projemin kaynak koduna buradan erişebilirsiniz.

Birçok farklı yol izleyerek öneri uygulaması geliştirmek mümkün ama bizim burada inceleyeceğimiz yöntemler Cold Start problemine çözüm öneren bir yaklaşım olacak. Cold Start problemi, kullanıcı hakkında hiçbir bilgiye sahip değilken (yeni kaydolmuş bir kullanıcı) öneri yapma sorunudur. Bu projemizde kullanıcıdan çok az bilgi alarak (örneğin kullanıcının yalnızca bir kategoriyi seçmesi) elde var olan datadan mantıklı öneriler yapmaya çalışacağız.

Gerekenler:

  • Python 3
  • numpy
  • pandas
  • nltk

Bu yazımızda Python programlama dilini bildiğinizi varsayarak ilerleyeceğim, ayrıca bu serideki asıl amaç öneri uygulaması ve farklı formüller ve tekniklerle öneri yapan bir sistem oluşturmak olduğu için, yazılan Python kodunun detaylarına fazla girmeyeceğim. Ayrıca Python dilinde çok uzman olmadığım için yazdığım bazı kısımlar muhtemelen daha iyi yazılabilirdi. Eğer değiştirmemi istediğiniz bir kısım olursa yorum yazarak beni haberdar ederseniz memnun olurum :)

4 farklı versiyon geliştirerek her birinde öneri sistemimizi farklı açıdan geliştirip daha kapmsalı bir hale getireceğiz. İlk versiyonumuzda Cosine Similarity kullanarak öneri yapacağız.

Yazacağımız öneri uygulaması, verilen gezi türüne göre 5 farklı şehir öneren bir sistem olacak. Tabi bu uygulama için izleyeceğimiz yöntemleri uygulayarak başka türde öneriler yapan sistemler geliştirmekte mümkün.

Sistemin baz alacağı veri setini buradan indirebilirsiniz.

Elimizdeki veri setindeki bazı özellikler (feature) gerçek verilerken bazıları ise deneme amaçlı benim rastgele eklediğim verilerden oluşuyor. Genel olarak veri setimiz 25 sehirden olusan bir veri seti. Setimizdeki her veri şu featurlara sahip: city, popularity, description, image, rating, rating_count, positive_review, negative_review. Veri setimizdeki özellikler ve değerleri ilk 5 şehir için aşağıda ki resimde gösterilmektedir.

Şehir veri seti özeti

Yukarda belirttiğim featurelardan city, popularity, description ve image bilgilerini Tripadvisor sitesindeki şehir bilgilerini yansıtıyor (tabi zamanla bilgiler siteden farklılık gösterecektir). Bunlar haricinde olan rating, rating_count, positive_review ve negative_review featureları ise rastgele değerler içeriyor. Dilerseniz her bir feature’ın ne işe yaradığını tek tek inceleyelim.

  • city: Şehir ismi
  • popularity: Şehir için kaydedilmiş review sayısı
  • description: Şehir hakkında bilgi veren küçük blog yazısı
  • image: Şehir background image url
  • rating: Şehrin sahip olduğu ortalama rating değeri 0–10 skalasında
  • rating_count: Kaç kullanıcıdan rating alındığı
  • postive_review: Girilen pozitif inceleme sayısı
  • negative_review: Girilen negatif inceleme sayısı

Veri setimizi ve sahip olduğumuz featureları öğrendiğimize göre artık başlayabiliriz. İlk versiyonumuzda yalnızca, city ve description featurelarini kullanarak ilerleyeceğiz.

Versiyon-1

İlk geliştireceğimiz versiyon yalnızca veri setindeki girdilerin description (açıklama) feature’ını baz alarak öneriler verecek bir sistem olacak. Bu sistem kullanıcının seçtiği gezi türüne bağlı olan keywordler (anahtar kelime) ile şehir açıklamaları arasındaki cosine similarity (cosinus benzerliği) değerini hesaplayarak en yüksek değere sahip olan 5 şehri kullanıcılara önerecek.

Cosine Similarity

Yukarda belirtilen benzerliği Cosine Similarity kullanarak hesaplayacağız. Cosine Similarity iki vektör arasındaki cosinus açısını çok boyutlu bir uzayda hesaplayarak vektörler arasındaki benzerliği ölçme metodudur. Cosine Similarity iki vektörün dot productunun, vektörlerin büyüklüklerinin çarpımına bölünmesiyle elde edilir. Aşağıda Cosine Similarity formülünü ve iki vektör arasındaki açıyı görsel olarak ifade eden figür’ü görebilirsiniz. 2 vektör arasındaki açı ne kadar küçükse, bu iki vektör birbirine o derecede benzerdir diyebiliriz. Bu method’a projemizin ilerleyen kısımlarında tekrar değineceğiz ama daha detaylı bilgi almak için [1], [2] referanslarına bakabilirsiniz.

Cosine Similarity Formülü
A ve B vektörleri için Cosine Similarity Formülü
3 boyutlu uzayda A ve B vektörleri arasındaki benzerlik

Preprocessing (Ön işlem)

Öncelikle elimizde olan veri setini kullanıma hazır bir hale getirebilmek için bazı işlemler gerçekleştirmemiz gerekiyor. Veri setimizinde içinde bulunduğu bir klasörde pre_processing.py adında bir Python dosyası oluşturalım.

Öncelikli olarak geliştireceğimiz recommender system sadece description feature’ını baz alarak önerilerde bulunacağı için veri setimizdeki girdilerin description featurelar’ını biraz temizlememiz gerekiyor.

İlk olarak ingilizcede stop words olarak adlandırılan kelimeleri şehir betimlemelerinden sileceğiz. Stop words, her yazıda sıkça rastlanan ama kendi başına pek bir anlam ifade etmeyen kelimelere denmektedir. (the, for, an, a, or, what vb). Bunu yapmamızdaki amaç, gereksiz olan kelimelerin çok fazla geçtiği şehir betimlemelerindeki benzerlik skorunun düşmesini engellemek. Çünkü cosine similarity hesaplamasında betimlemelerdeki her bir kelime uzayda ayrı bir boyut oluşturacağı için, bu tarz gereksiz kelimeler benzerlik skorunu negatif yönde etkileyebilir.

import numpy as np
import pandas as pd
from nltk.corpus import stopwords
def clear(city):
city = city.lower()
city = city.split()
city_keywords = [word for word in city if word not in stopwords.words('english')]
merged_city = " ".join(city_keywords)
return merged_city

Yukardaki clear methodu sayesinde veri setimizdeki şehir betimlemelerini temizleyebiliriz. Method sırasıyla şu şekilde çalışıyor:

  • city adında bir String parametresi kabul ediyor
  • Alınan Stringde ki tüm harfleri öncelikle .lower() methodu yardımıyla küçültüyor
  • Sonrasında .split() ile tüm kelimeleri ayırarak bir String listesi oluşturuyor
  • Sonrasında ise stopwords içersinde olan tüm kelimeleri bu listeden çıkararak city_keywords değişkenini elde ediyoruz.
  • Daha sonra tüm bu kelimeleri aralarında boşluk bırakarak bir String haline getirip (merged_city) methodun çağrıldığı yere dönüyor.

Şimdi bu metodu veri setimizdeki her bir şehre uygulayarak betimlemeleri temizleyelim. Aşağıdaki kod bloğunu clear metodunun altına ekleyelim:

for index, row in df.iterrows():
clear_desc = clear(row['description'])
df.at[index, 'description'] = clear_desc
updated_dataset = df.to_csv('city_data_cleared.csv')

Bu kod bloğu her bir şehir betimlemesini temizleyerek, temizlenmiş verileri city_data_cleared.csv adında bir dosyaya kaydedecek. Bundan sonraki işlemlerimizde o veri setini kullanacağız.

pre_processing.py gist:

pre_processing.py

Cosine Similarity ile benzerlik hesaplama

Artık şehir betimlemelerini temizlediğimize gore, benzerlik skorunu hesaplayacak olan metodu yazmaya baslayabiliriz. cosine_similarity.py adında bir python dosyasi olusturalim.

Daha onceden belirttiğim gibi, yazacağımız metod iki ayrı string deki kelimelerin benzerliğine gore skor veren bir metod olacak. İlk olarak verilen bu iki ayrı String kelimelerden olusan vektörlere cevireceğiz. Sonrasında herhangi bir vektörde var olan herhangi bir kelime uzayda ayrı bir boyut oluşturacak, ve eğer bir vektörde var olan bir kelime diğer vektörde yoksa, o kelime icin öteki vektörün uzayındaki kelimenin boyutuna karşılık gelen deger 0 olacak.

Not: Cosine similarity, kelimelerin bir metinde birden fazla gecmesinden çok etkilenmeyen bir metod, bizim açımızdan kelimelerin bir kere geciyor olması yeterli olacağı icin bunun pek bir onemi yok, ama eğer ilerde siz başka bir uygulamada buna önem vermek isterseniz, Pearson correleation metoduna bakmanızı öneririm.

Daha generic ve tekrar kullanilabilir olması icin cosine_similarity.py dosyamıza yazacağımız kodlari CosineSimilarity adında bir sınıf altında yazalım:

import re, math
from collections import Counter
class CosineSimilarity:
def __init__(self):
print("Cosine Similarity initialized")

@staticmethod
def cosine_similarity_of(text1, text2):
first = re.compile(r"[\w']+").findall(text1)
second = re.compile(r"[\w']+").findall(text2)
vector1 = Counter(first)
vector2 = Counter(second)
common = set(vector1.keys()).intersection(set(vector2.keys())) dot_product = 0.0 for i in common:

dot_product += vector1[i] * vector2[i]
squared_sum_vector1 = 0.0
squared_sum_vector2 = 0.0
for i in vector1.keys():
squared_sum_vector1 += vector1[i]**2
for i in vector2.keys():
squared_sum_vector2 += vector2[i]**2
magnitude = math.sqrt(squared_sum_vector1) * math.sqrt(squared_sum_vector2) if not magnitude:
return 0.0
else:
return float(dot_product) / magnitude

Yazdığımız cosine_similarity_of metodu aşağıdaki sekilde çalışıyor:

  • Öncelikle verilen iki Stringi Regex yardımıyla kelimelerine ayırıyor
  • Daha sonra iki string icinde iki ayrı, kelimeleri ve kaç kere geçtiklerini içeren bir dictionary oluşturuyor (örn: nice: 4)
  • Daha sonra her iki vektörde de ortak bulunan kelimeleri elde ediyor
  • Yukarda Cosine Similarity başlığı altında verilen formulu izleyerek benzerliği hesaplayıp bunu metodun sonunda donuyor

cosine_similarity.py gist:

cosine_similarity.py

Öneri Motoru yazimi

Artık sehir betimlemelerimizi temizleyip cosine similarity hesaplayan metodumuzu yazdığımıza gore, birinci versiyon icin öneri yapacak olan motorumuzu yazmaya baslayabiliriz.

İlk versiyonumuzda sadece benzerlik skoruna gore öneri yapacağımız icin motor sınıfımız küçük olacak, ama sonraki versiyonlarda ayni kodları geliştireceğimiz icin ayrı bir sınıf olarak baslamakta fayda var.

recommender_engine.py:

recommender_engine.py

get_recommendations(keywords) metodu sırasıyla aşağıdaki gibi çalışıyor:

  • Öncelikle, sehir betimlemelerinin benzerliğini hesaplayabileceği keywords adında String parametresi alıyor
  • Her sehir icin verilen keywords ile olan benzerlik skorunu hesaplıyor ve bunları sehir indexi — skor seklinde bir dictionary de tutuyor.
  • Sehirlerin; city, popularity, description ve score featurelarini içeren boş bir data frame oluşturuyor.
  • En yüksek skora sahip 5 sehri bu data frame ekliyor
  • Son olarak, bu data frame’i json a çevirip donuyor.

Request kodu

Öneri yapan ve cosine similarity hesaplayan sınıflarımız olduguna göre artık bunları test etmenin zamanı geldi. request.py adında bir python dosyası oluşturalım.

Öneri uygulamamızı 3 ayrı kategori altında deneyeceğiz. Bunlar;

  • Culture, Art and History (Kültür, Sanat ve Tarih)
  • Beach and Sun (Kumsal ve Güneş)
  • Nightlife and Party (Gece hayati ve parti)

Ben veri setimizdeki sehir betimlemelerini inceleyerek, her üç kategori icin keywordleri sırasıyla aşağıdaki gibi belirledim:

  • [history historical art architecture city culture]
  • [beach beaches park nature holiday sea seaside sand sunshine sun sunny]
  • [nightclub nightclubs nightlife bar bars pub pubs party beer]

3 ayrı kategori icin request gönderecek 3 ayrı metodu request.py dosyamıza aşagıdaki gibi yazalım:

from recommender_engine import RecommenderEngineculture_keywords = "history historical art architecture city culture"
beach_n_sun_keywords = "beach beaches park nature holiday sea seaside sand sunshine sun sunny"
nightlife_keywords = "nightclub nightclubs nightlife bar bars pub pubs party beer"
def get_recommendations(keywords):
result = RecommenderEngine.get_recommendations(keywords)
return result
def get_top_5_city_names_out_of_json(json_string):
list = json.loads(json_string)
result = []
max = len(list)
i = 0
while i < max:
result.append(list[i]['city'])
i += 1
return resulttop_5_cultural_cities = get_recommendations(culture_keywords)
city_names_for_cultural = get_top_5_city_names_out_of_json(top_5_cultural_cities)
print(city_names_for_cultural)
print("#################")
top_5_summer_cities = get_recommendations(beach_n_sun_keywords)
city_names_for_summer = get_top_5_city_names_out_of_json(top_5_summer_cities)
print(city_names_for_summer)
print("#################")
top_5_party_cities = get_recommendations(nightlife_keywords)
city_names_for_party = get_top_5_city_names_out_of_json(top_5_party_cities)
print(city_names_for_party)
print("#################")

get_recommendations metodu gönderilen keywordlere gore gelen öneri json stringini donerken, get_top_5_city_names_out_of_json metodu ise donen önerilerden sehir isimlerini ve skorlarını ayrıştırıp geri donuyor. (ikinci metodun tek amacı print ettigimiz zaman sadece sehir isimlerini ve skoru görebilmek, çünkü hatırlarsanız recommender_engine her sehir icin birden farklı feature özelligi donuyor ve hepsini print ettirmek su an gereksiz.)

request.py gist:

request.py

Kodu çalıştırdığımızda 3 ayrı kategori icin önerileri ve skorlarını alacağız fakat, aşağıda sadece Kültür ve Sanat kategorisi icin olan sonuclar gösterilmektedir:

[('Athens', 0.21629522817435007),
('St. Petersburg', 0.16666666666666666),
('Stockholm', 0.14962640041614492),
('Milan', 0.140028008402801),
('Rome', 0.12171612389003691)]

Atina sehri icin benzerlik skoru %21,6 iken, Roma sehri icin gelen benzerlik skoru %12,2 civarinda. Benzerlik skoru beklediğinizden daha düşük gelmiş olabilir, bunun nedeni sehir betimlemelerinde doğal olarak bizim manuel olarak girdiğimiz keywordlerden farklı kelimelerin var olması. Farklı kelimeler uzayda farklı boyutların oluşmasına neden oluyor ve keywordlerimizde bu boyutlara karşılık gelen değerlerin olmaması, sonuçları düşürüyor. Eğer keywords listesine farklı kelimeler eklerseniz veya bazı kelimeleri silerseniz, sonuçların değişeceğini görebilirsiniz.

Sonuç

Bu versiyonda üç farklı kategori icin, seçilen kategorideki keywordler ile sehir betimlemeleri arasındaki cosine similarity skorunu hesaplayarak gezilecek sehir önerisi yapan bir öneri uygulaması geliştirdik.

Her ne kadar genel olarak benzerlik skorları düşük olsada, verilen Kültür ve Sanat kategorisi icin önerilen top 5 sehir incelendiğinde, yazdiğimiz sistemin verilen kategoriye uygun sehirler döndüğünü görebiliyoruz. Diğer kategoriler incelendiğinde gelen önerilerin verilen kategori icin mantıklı ve uygun sehirler oldugunu görülebilir. Sonuçları teyid etmek icin sehir betimlemelerini okuyabilirsiniz :)

İlk versiyonumuzun sonuna geldik. Bu versiyon için geliştirdiğimiz kodlara şuradan ulaşabilirsiniz.

Bir sonraki versiyonda cosine similarity ile birlikte farklı bir formül uygulayarak, Rating bilgisini hesaba katarak nasıl öneri yapılabileceğini inceleyeceğiz.

Versiyon-2 (Rating Katkısı)

Bu versiyonda veri setimizdeki rating feature’ını da kullanarak, öneri sistemimizi daha dinamik ve iyi bir hale getirmeye çalışacağız. Kötü rating’e sahip içerikleri önermek istemeyiz değil mi? :)

CS ve rating katkısıyla skor hesaplama

İlk olarak kaç adet rating verildiğini önemsemeyeceğiz. Bir önceki versiyonda olduğu gibi gene CS skorunu hesaplayacağız ama bu sefer ek olarak son skor hesaplamasında rating bilgisinide hesaba katacağız. Öncelikle, rating katkısını belirleyecek olan bir method yazacağız. Bu metodumuz iki parametre alacak, Q ve r. r parametresi şehir rating’i, Q parametresi ise rating katkısının son skora ne kadar etki edeceğini belirleyen bir değer olacak. Q parametresini artırıp azaltarak, rating değerinin, CS skoruna kıyasla son skora ne kadar katkı sağlayacağını belirleyeceğiz.

Yeni metodumuz son skoru, CS skoruna pozitif veya negatif katkı sağlayarak hesaplayacak. Rating katkısı eğer şehir rating’i 5'in üzerindeyse pozitif (5 veya üzerinde ratinge sahip olan şehirlerin beğenildiği varsayılıyor), altında ise negatif olacak (5 altındaki şehirlerin beğenilmediği ). Rating değeri 0 ila 10 arasında değişirken, rating katkı output’u ise -Q ve +Q arasında bir değer olacak.

Örneğin Q=10 olarak verilirse, son skor, en yüksek rating için (10): CS skoru + CS skorunun % 10'u olarak hesaplanırken, en düşük rating için (0): CS skoru — CS skorunun %10' olarak hesaplanacak.

Metodda kullanılacak olan formül, aşağıdaki grafikte, verilen rating değerinin mavi eğride karşılık geldiği noktayı bularak bunu katkı değeri olarak dönecek. Aşağıda Q=10 için metodumuzun ne tür katkı değeri sağlayacağı görsel olarak gösterilmiştir:

Rating katkısı hesaplayan metod (Q=10)

Şimdi rating_extractor.py adında bir dosya oluşturalım ve aşağıdaki kodu ekleyelim:

class RatingExtractor:
def __init__(self):
print("initialized")
#Returns value between -q and q. for rating input between 0 and 10.
#Parameters:
#rating: indicates the rating for the destination
#q: indicates the percentage of rating for general score. (default is 10.)
@staticmethod
def get_rating_weight(rating, q=10):
if rating > 10 or rating < 0:
return None
else:
m = (2*q) / 10 #10 because rating varies between 0 and 10
b = -q
return (m*rating) + b

Metodlardaki yorumlar ingilizce olduğu için kusura bakmayın lütfen, ama zaten her metodu detaylı olarak anlatmaya çalışıyor olacağım.

get_rating_weight() metodu verilen rating ve Q parametrelerine göre hesaplamalar yaparak rating katkısını hesaplayıp geri dönen bir metod. Daha öncede belirttiğim gibi, bu metod hem pozitif hem negatif değerler dönebilir. Döndüğü değere göre, son skor’a ya pozitif yada negatif bir katkı sağlıyor olacak. (Q parametresinin varsayılan değeri 10 olarak ayarlanmıştır.)

Recommender Engine için yeni metod geliştirme

Simdi Recommender Engine sinifimiza, cosine similarity skorunu ve rating katkisini kullanarak genel skor hesaplayacak bir method yazacagiz. Asagidaki metodu RecommenderEngine sinifina ekleyelim:

def calculate_final_score(cs, r):
amount = (cs / 100) * r
return cs + amount

Method asagidaki gibi calisiyor:

  • CS skoru ve rating katkisi r parametrelerini aliyor
  • CS skorunun % +- r lik kismini amount olarak hesapliyor
  • Hesaplanan amount’u CS skoruna ekleyerek dönüyor.

Amount pozitif veya negatif bir deger olacagi icin, son skorumuz rating katkisina bagli olarak ya CS skorunu artiracak yada azaltacak.

Bu yaklaşım rating bilgisini kullanmamız için faydalı olacak fakat şu durumu belirtmekte fayda var. Rating katkısına dayalı olarak son skor hesaplaması, CS skoruna bağlı bir şekilde gerçekleşiyor. CS skorunun belirli bir yüzdesi üzerinden son skor hesaplandığı için; özellikle get_rating_weight() metodu icin yüksek Q değerleri girildiğinde, CS skoru (benzerliği) yüksek olan şehirler, düşük olan şehirlere göre daha fazla etkilenecekler.

Şimdi RecommenderEngine sınıfına yeni metodlarımızı kullanarak öneri yapması için yeni bir metod yazalım. (Birinci versiyonda yazdığımız metodu hala sınıfta tutuyoruz)

RecommenderEngine ikinci versiyon metodu

get_recommendations_include_rating(keywords) metodu ilk versiyonda geliştirilen get_recommendations(keywords) metoduna benzer bir şekilde çalışacak. Fakat bu yeni metod önerileri, yeni geliştirdiğimiz metodları kullanarak, hem CS skorunu hem rating katkısını hesaba katarak yapacak. Adım adım metodumuzun nasıl çalıştığına bakalım:

  • Keywords parametresi alıyor ve aşağıdaki işlemleri veri setindeki tüm şehirler için uyguluyor
  • CS skorunu hesaplıyor
  • Rating katkısını Q=10 olarak hesaplıyor
  • CS skoru ve rating katkısını kullanarak calculate_final_score methodu ile son skoru hesaplıyor
  • Son skora göre en yüksek skora sahip 5 şehri JSON’a çevirip dönüyor.

Request kodu

Öncelikle RecommenderEngine’den önerileri alacak bir method yazalım:

def get_recommendations_include_rating(keywords):
return RecommenderEngine.get_recommendations_include_rating(keywords)

Şimdi 3 kategorimiz içinde, yeni metodu kullanarak öneri alacak olan 3 farklı request yazalım:

# Version 2 requests are below:top_5_cultural_with_rating = get_recommendations_include_rating(culture_keywords)
city_names_for_cultural_rating = get_top_5_city_names_out_of_json(top_5_cultural_with_rating)
print(city_names_for_cultural_rating)
print("#################")
top_5_summer_with_rating = get_recommendations_include_rating(beach_n_sun_keywords)
city_names_for_summer_rating = get_top_5_city_names_out_of_json(top_5_summer_with_rating)
print(city_names_for_summer_rating)
print("#################")
top_5_party_with_rating = get_recommendations_include_rating(nightlife_keywords)
city_names_for_party_rating = get_top_5_city_names_out_of_json(top_5_party_with_rating)
print(city_names_for_party_rating)
print("#################")

Bu kod önerilen şehirleri ve son skorlarını ekrana yazdıracak, request.py çalıştırıp gelen sonuçları inceleyebilirsiniz.

Bu yazımızda sadece Kültür, Sanat ve Tarih kategorisini, iki farklı bakış açısından inceleyeceğiz. İlk olarak, bir önceki versiyonda yazdığımız sadece CS skoru ile öneri yapan metod ile, yeni yazdığımız hem CS skoru, hem rating katkısını kullanarak son skor hesaplayan metodu karşılaştıracağız.

get_recommendations ve get_recommendations_include_rating metodlarının karşılaştırılması:

Aşağıdaki kodu iki metodu karşılaştırma amacıyla yazdığım için request.py sınıfına dahil etmedim, dilerseniz kopyalayıp çalıştırabilirsiniz:

top_5_cultural_cities = get_recommendations(culture_keywords)
city_names_for_cultural = get_top_5_city_names_out_of_json(top_5_cultural_cities)
print(city_names_for_cultural)
print("#################")
top_5_cultural_with_rating = get_recommendations_include_rating(culture_keywords)
city_names_for_cultural_rating = get_top_5_city_names_out_of_json(top_5_cultural_with_rating)
print(city_names_for_cultural_rating)
print("#################")

İki metodun çıktısı aşağıdaki gibi:

[('Athens', 0.21629522817435007),
('St. Petersburg', 0.16666666666666666),
('Stockholm', 0.14962640041614492),
('Milan', 0.140028008402801),
('Rome', 0.12171612389003691)]
#################[('Athens', 0.22927294186481106),
('Stockholm', 0.1556114564327907),
('St. Petersburg', 0.15333333333333332),
('Milan', 0.15123024907502508),
('Rome', 0.13145341380123987)]

Yukarıda, her iki farklı içinde farklı skor ve şehir sıralamaları verilmiştir. Gördüğünüz gibi, yeni geliştirdiğimiz metodda (alttaki) Stockholm ikinci sıraya yükselirken, St. Petersburg üçüncü sıraya geriledi. Gelin bunun nedenini inceleyelim:

Veri setimizde görüldüğü üzere, Stockholm’ün rating’i 7 iken, St. Petersburg’un ratingi 1. Bu yüzden algoritmamız St. Petersburg için son skoru, Cs skoruna göre daha düşük hesaplarken, Stockholm için ise son skoru daha yüksek hesaplıyor. Bu yüzden son skorda Stockholm, St. Petersburg’u geçerek ikinci sıraya yükseliyor. Burada görebiliyoruzki, yazdığımız metod ve formüller, yüksek ratingli içeriklerin skorunu artırırken, düşük ratingli içeriklerin skorunu azaltıyor. Veri setimizdeki diğer şehirlerin rating bilgisini de inceleyerek, genel olarak skorlardaki değişimlerin nedenlerini gözlemleyebilirsiniz.

get_recommendations_include_rating metodunun Q = 10 ve Q = 100 için karşılaştırılması:

Şimdi yeni metodumuzu farklı Q parametreleriyle karşılaştıracağız. Hatırlarsanız, rating katkısı, Q parametresinin değeriyle doğru orantılı olarak değişiyor. Bir önceki karşılaştırmada yazdırdığımız gibi, Q=10 için, Kültür, Sanat ve Tarih kategorisinde son skor hesaplamasının en yüksek skorlu 5 şehri:

[('Athens', 0.22927294186481106),
('Stockholm', 0.1556114564327907),
('St. Petersburg', 0.15333333333333332),
('Milan', 0.15123024907502508),
('Rome', 0.13145341380123987)]

Şimdi Q parametresini 100 yaparak sonuçları inceleyeceğiz. recommender_engine.py dosyasına gidip get_recommendations_include_rating metodundaki 10 sayısını 100 olarak güncelleyerek parametre değerini artırabilirsiniz:

rating_contribution = RatingExtractor.get_rating_weight(rating,100)

Şimdi yeni sonuçlarımıza bakalım:

[('Athens', 0.3460723650789601),
('Milan', 0.2520504151250418),
('Rome', 0.21908902300206645),
('Stockholm', 0.2094769605826029),
('Venice', 0.17777777777777776)]

Q parametresini 100 yaptığımızda, sonuçlarımızın çok daha farklı olduğunu görebiliyoruz:

  • St. Petersburg şehri artık ilk 5 de bile değil, 1 ratingi olduğu için Q parametresi de yükselince, son skoru tamamen düşük bir değer aldı.
  • Stockholm dördüncü sıraya düşerken, Milan ve Roma, ikince ve üçüncü sıralara yükseldi, aşağıda görülebileceği gibi Milan ve Romanın rating’i Stockholm’e göre daha yüksek olduğu için
Roma, Milan ve Stockholm için rating kıyaslaması

Diğer şehir kategorileri içinde farklı Q parametreleriyle sonuçların nasıl değiştiğini incelemenizi öneririm.

Versiyon-2 Sonucu

İkinci versiyonumuzda Cosine benzerliğinin yanı sıra rating bilgisini de kullanarak şehir önerisi yapan yeni bir method geliştirdik. Öneri sistemlerinde rating gibi bilgileri kullanmak oldukça önemli, çünkü genellikle insanlar tarafından beğenilen içerikleri önermek isteriz.

İkinci versiyonun tüm kodlarına buradan ulaşabilirsiniz.

Bir sonraki versiyonda verilen rating sayısınıda hesaba katarak öneri sistemimizi daha iyi bir hale getirmeye çalışacağız.

Versiyon-3 (Rating Eşik Değeri)

Bir içeriğin yüksek rating’e sahip olması, bu rating’in güvenilir olduğu anlamına gelmez. A ve B adında iki farklı içerik olduğunu düşünün. A, 500.000 kişinin verdiği rating sonucunda 4.7 rating’e sahip ve B ise 10 kişinin verdiği rating sonucunda 5 ratingi’ne sahip. Hangi içeriği bir arkadaşınıza önermek isterdiniz? B içeriğinin sahip olduğu 5 ratingi, sadece 10 kişinin rating verdiği göz önüne alındığında ne kadar güvenilir olabilir? rating_count feature’ı sayesinde; ratingler için bir eşik parametresi oluşturacağız ve öneri sistemimiz, rating sayısı bu parametreden düşük olan içeriklere (şehirler) rating katkısı hesaplanırken çok fazla ağırlık yüklemeyecek. Bu sayede az sayıda kişiden rating almış şehirlerin rating bilgisi pek fazla kaale alınmamış olacak.

Rating count feature’ı ile rating ağırlık hesaplanması

Multiplier formülü

Yukarıdaki formül sayesinde hesaplanan M çarpanı, rating katkısı ile çarpılarak, son öneri skoru hesaplanmasında kullanılmak üzere rating ağırlığını elde etmemize yardımcı olacak. T eşik sayısını, c ise bir şehrin aldığı rating sayısını temsil ediyor. Bu formül aşağıdaki gibi çalışacak şekilde tasarlanmıştır:

  • M değeri 0.0 ve 1.0 arasında değişebilir
  • T ve c parametreleri eşit olduğu durumda, M her zaman 0.50 ye eşittir.

Bu formülde e sayısının kullanılması için herhangi bir özel durum bulunmamakta, bir başka sayı kullanarakta formülü oluşturabilirdik (o zaman 0,68 sayısı değişmek zorunda kalırdı). Havalı görünmesi için e sayısını kullandım :P

Bu formülün en önemli noktası, T (eşik) ve c (rating sayısı) değerleri birbirine eşit olduğunda 0.50 değerini veriyor olması. Bir şehrin aldığı rating sayısı bizim girdiğimiz eşik değerinden düşükse, M değeri 0.0–0.50 aralığında, eğer eşik değerinden yüksekse, M değeri 0.50–1.0 arasında olacak. Ama rating sayısı ve eşik değeri ne olursa olsun, M değeri asla 1.0 dan yüksek olamayacak.

Şimdi rating_extractor.py dosyasına gidelim ve yeni bir metod yazalım. Burada yalnızca rating katkısını M ile çarpacağız fakat, daha önce geliştirdiğimiz metoduda ilerde olduğu gibi kullanabilmeniz adına bu yeni yazacağımız metodu ayrı olarak yazacağız.

İlk olarak e’yi dosyamıza import edeceğiz:

from math import e

Sonra, RatingExtractor sınıfına aşağıdaki metodu ekleyelim:

@staticmethod
def get_rating_weight_with_quantity(rating, c, T, q=10):
if rating > 10 or rating < 0:
return None
else:
m = (2*q) / 10 #10 because rating varies between 0 and 10
b = -q
val = (m*rating) + b
M = e**((-T*0.68)/c) return val * M

Metod aşağıdaki gibi çalışacak:

  • rating, c (rating sayısı), T (eşik) ve Q parametrelerini alıyor.
  • rating ve Q parametrelerini önceki bölümlerde görmüştük.
  • rating katkısını hesaplıyor
  • Verilen parametrelere göre M çarpanını hesaplıyor
  • rating katkısını M ile çarparak rating ağırlığını dönüyor.

RecommenderEngine sınıfında yeni metod geliştirme

Şimdi recommender_engine.py dosyasını açalım ve RecommenderEngine sınıfına yeni bir metod ekleyelim (önceki bölümlerde geliştirdiğimiz metodları hala tutuyoruz). Bu ekleyeceğimiz metod aslında önceki bölümlerde geliştirdiğimiz metodlara oldukça benziyor fakat bu sefer, şehir betimlemesi ve rating ile birlikte, rating sayısı ve T (eşik değeri) parametrelerini kullanacağız.

get_recommendations_include_rating_threshold metodu

Metodumuz aşağıdaki gibi çalışıyor:

  • Keywords parametresi alıyor, ve veri setindeki tüm şehirler için aşağıdaki adımları gerçekleştiriyor
  • CS skorunu hesaplıyor.
  • Her şehir için betimleme, rating, rating sayısı, eşik T = 1.000.000 (Veri setimizde rating sayısı 100 bin ila 5 milyon arasında değiştiği için 1 milyon değerini seçtim) ve Q=10 değerleriyle rating ağırlığını hesaplıyor.
  • CS skoru ve rating ağırlığıyla calculate_final_score metodunu (önceki bölümde geliştirilmişti) çağırarak, son skoru hesaplıyor.
  • En yüksek skora sahip 5 şehri JSON’a çevirip dönüyor.

Request kodu

Sırada request.py dosyasına yeni metodumuzu kullanarak 3 farklı kategori için request göndermek var.

Öncelikle, yeni metodumuzu kullanarak önerileri alacak bir metod yazalım:

def get_recommendations_include_rating_count_threshold(keywords):
return RecommenderEngine.get_recommendations_include_rating_count_threshold(keywords)

Şimdi 3 kategori için önerileri alacak olan 3 request yapalım:

# Version 3 requests are below:top_5_cultural_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(culture_keywords)
city_names_for_cultural_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_cultural_with_rating_count_threshold)
print(city_names_for_cultural_rating_count_threshold)
print("#################")
top_5_summer_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(beach_n_sun_keywords)
city_names_for_summer_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_summer_with_rating_count_threshold)
print(city_names_for_summer_rating_count_threshold)
print("#################")
top_5_party_with_rating_count_threshold = get_recommendations_include_rating_count_threshold(nightlife_keywords)
city_names_for_party_rating_count_threshold = get_top_5_city_names_out_of_json(top_5_party_with_rating_count_threshold)
print(city_names_for_party_rating_count_threshold)
print("#################")

Yukardaki kod bloğu, 3 kategori içinde son skorlarına bağlı olarak önerileri yazdıracak. request.py çalıştırarak tüm kategoriler için sonuçları görebilirsiniz. Ama biz bu yazımızda yalnızca Kültür, Sanat ve Tarih kategorisi için sonuçları inceleyeceğiz.

Farklı eşik değerleriyle sonuçların kıyaslaması

Gelin, Kültür Sanat ve Tarih kategorisi için farklı T değerleriyle deneysel requestler yapalım. Threshold değerini RecommenderEngine sınıfındaki get_recommendations_inçlude_rating_count_threshold metodundan değiştirebilirsiniz. Ayrıca eşik etkisini daha iyi görebilmek için Q değerinide 100'e arttıralım (önceki bölümlerde anlatıldığı gibi Q yükseldikçe son skor hesaplamasında rating’in etkisi CS skoruna oranla artıyor).

T = 100.000:

[('Athens', 0.33318171469723395),
('Milan', 0.24587898720843948),
('Rome', 0.21192640793273687),
('Stockholm', 0.18358642633975064),
('Venice', 0.17262307588744202)]

T = 1.000.000:

[('Athens', 0.26188415260156817), 
('Milan', 0.2035910531885378),
('Rome', 0.16707033294390228),
('Stockholm', 0.14983344608755947),
('Barcelona', 0.14757848986361075)]

T = 2.500.000:

[('Athens', 0.2257870828894539), 
('Milan', 0.16719580286435054),
('St. Petersburg', 0.158824470447676),
('Stockholm', 0.14962644254339),
('Rome', 0.13613352041126298)]

Yukardaki sonuçlardan görüldüğü üzere, önerilerdeki 5. sıradaki şehir, eşik değeri 100 bin ve 1 milyon olmasına göre değişiyor. Eşik değeri düşük olduğunda beşinci şehir Venedik iken, değer yüksek olduğunda beşinci şehir Barselona. Bunun nedenini görelim:

İki şehrin ratingi de 8 ama, Barselona daha fazla rating sayısına sahip, ayrıca Venedik, Barselonaya kıyasla daha fazla CS skoruna sahip. Bu yüzden eşik değeri 100.000 olduğunda, iki şehirde iyi miktarda rating katkı puanına sahip ve Venediğin CS skoru daha yüksek olduğundan, beşinci sırada Venediği görüyoruz.

Ama eşik değeri 1.000.000 olduğunda, rating katkı skorları aşağıdaki gibi hesaplanıyor (Q=100):

  • Barcelona: 34
  • Venice: 26.8

Barselona daha fazla rating katkı puanına sahip ve Q değeride yüksek olduğu için, son skor hesaplandığında elde edilen değer Barselona için daha yüksek olduğundan, beşinci sırada Barselonayı görüyoruz.

Eşik değeri 2.500.000 olduğunda St. Petersburg’u 3. sırada görüyoruz. Ama daha düşük eşik değerlerinde St.Petersburg’u 4. yada 5. sırada bile göremiyorduk. Bunun nedenini araştırmayı sizlere bırakacağım. St. Petersburg şehri için veri setini inceleyip, yazdığımız metodların üzerinden tekrar geçerek, bunun nedenini anlamaya çalışın. Eğer bir sorunuz olursa bana sorabilirsiniz. :)

Bunun haricinde, parametre değerlerini değiştirip farklı değerlerle oynamanızı, veri setindeki değerleri incelemenizi ve aldığınız sonuçları tüm kategoriler içinde inceleyerek, yazdığımız metodların nasıl çalıştığını ve bu metodların öneri sistemlerindeki değerini anlamaya çalışmanızı öneririm.

Versiyon-3 Sonucu

Üçüncü versiyonda, öncelikle şehirlerin CS skorunu ve rating ve rating sayısı featurelarını kullanarak rating ağırlığını hesaplayan, daha sonra CS skoru ve rating ağırlığını kullanarak son skor hesaplayarak şehir öneren bir metod geliştirdik. Öneri sistemlerinde verinin güvenilirliği göz önünde bulunarak öneri yapılması gerektiğinden, yazdığımız metod sayesinde öneri sistemimizin nasıl daha yüksek sayıda (yüksek sayı uygulamadan uygulamaya değişiklik gösterecektir) feedback içeren içerikleri teşvik edebileceğini gördük.

Yazılan tüm kodlara buradan erişebilirsiniz.

Bir sonraki versiyonda, farklı türden feedbackleri işleyerek öneri yapan bir metod geliştireceğiz.

Versiyon-4

Bu versiyonda positive_review ve negative_review featurelarını da kullanarak öneri sistemimizi geliştirmeye devam edeceğiz.

Bu bölümde önceki bölümlere kıyasla, daha çok teori ve deneysel sonuçlar hakkında konuşacağız, eğer sadece kod ile ilgileniyorsanız. Uygulama kısmından başlayabilirsiniz.

Bazen uygulamalarımızda içeriklerimiz için birden farklı tipte feedback’e sahip olduğumuz durumlar olabilir, review ve rating gibi. Tahmin edebileceğiniz gibi, bu feedbackler aynı türde değil, rating feedback’i belirli sayısal bir aralık üzerinde (bizim uygulamamızda 0–10 arası) verilirken review feedback’i genellikle metin olarak verilir. Sahip olduğumuz reviewleri pozitif ve negatif olarak sınıflandırdığımız hayal edelim (belki verilen reviewleri pozitif/negatif olarak sınıflandırma üzerinde farklı bir yazı yazabiliriz), o zaman review feedback’i binary feedback (0 yada 1) olarak ele alınabilir.

Veri setimizde her şehir için positive_review ve negative_review adları altında her şehrin aldığı pozitif ve negatif review sayılarını gösteren featurelar mevcut.

Öneri uygulamalarının başa çıkması gerektiği sorunlardan biride farklı türden feedbackleri birlikte kullanarak daha anlamlı öneriler yapabilme. Bunu yapmak için farklı yöntemler mevcut olsada biz bu yazımızda, özel bir yöntemle alınan reviewleri rating’e dönüştürerek farklı türdeki feedbackleri bir arada kullanacağız.

Reviewleri ratinge çevirme

En basit yöntemle bir review’i ratinge dönüştürmek, pozitif ve negatif reviewler için belirli birer rating değeri belirlemek olurdu. Reviewler bu rating değeriyle dönüştürüldükten sonra, ortalama rating, asıl rating ve dönüştürülen rating hesaba katılarak tekrardan hesaplanabilirdi. Ama bu yaklaşım pek iyi bir yaklaşım olmazdı. Örneğin, ratingler 0 ve 10 olarak seçilmiş olsa, reviewlerin etkisi içerikler üzerinde çok fazla olurdu (özellikle bir içeriğin ortalama ratingi zaten 0 veya 10 a yakınsa). Bu ekstrem etkiyi azaltmak için farklı rating değerleri seçilebilirdi, eğer ratingler 2.5 ve 7.5 olarak seçilse, bu seferde farklı bir problem ortaya çıkacaktı. Ortalama değeri 7.5'in üzerinde olan bir içerik için, otomatik olarak 7.5 ratingine dönüştürülmüş pozitif bir review, pozitif olmasına rağmen, içeriğin ortalama ratinginden düşük olduğu için negatif bir etki oluştururdu. Aynı şekilde hali hazırda rating ortalaması 2.5'in altında olan içerikler içinde, otomatik olarak 2.5 değerine dönüştürülen negatif reviewler, pozitif etki gösterebilirdi. Bu sebeplerden dolayı, daha iyi bir method geliştirmekte fayda var.

Geliştireceğimiz method pozitif ve negatif reviewler için sırasıyla aşağıdaki gibi davranacak:

  • Her bir pozitif review için, içeriğin ortalama rating’i ile rating skalasında alınabilecek en yüksek değer (bizim uygulamamız için 10) arasındaki mesafe hesaplanıp sonra bu mesafenin yarısı, içeriğin ortalama ratingine eklenerek, pozitif bir review ratinge çevrilmiş olacak.
  • Her bir negatif review için, içeriğin ortalama rating’i ile rating skalasında alınabilecek en düşük değer (bizim uygulamamız için 0) arasındaki mesafe hesaplanıp, sonra bu mesafenin yarısı içeriğin ortalama ratinginden çıkarılarak, negatif bir review ratinge çevrilmiş olacak.

Pozitif ve negatif reviewleri ratinge çevrilmek için kullanılacak formüller Rp ve Rn olarak sırasıyla aşağıda verilmiştir (r içeriğin ortalama rating değeri):

Pozitif bir review için rating değer dönüşümü
Negatif bir review için rating değer dönüşümü

Örneğin, ortalama ratingi 6 olan bir içeriğe verilen her bir negatif review 3 değeriyle ratinge çevirilerek ratinglerin arasına eklenirken, her bir pozitif review 8 değeriyle çevrilere eklenecek. Sonra ortalama değer skor hesaplamasında kullanılmadan önce, içeriğin hali hazırda sahip olduğu ratingler + yeni dönüştürülen ratingler hesaba katılarak tekrardan hesaplanacak. Review feedback dönüşümü sonuçları farklı rating, rating sayısı ve review sayıları için aşağıdaki tabloda verilmiştir. (tabloyu ingilizce olarak hazırladığım seriden aldığım için sütun başlıkları türkçe değil maalesef)

Ortalama rating ve reviewler için rating değer hesaplaması

Reviewler hesaba katıldıktan sonra tekrar hesaplanan rating değerine bakıldığında, içeriğin ratingi alınabilecek en yüksek ratinge yakın olduğunda ve pozitif ve negatif review sayıları arasında çok fark olmadığında, pozitif review, negatif reviewden fazla olmasına rağmen, metodumuz negatif bir etkiye sahip oluyor. Aynı şekilde içeriğin ratingi alınabilecek en düşük ratinge yakın olduğunda ve negatif ve pozitif review sayıları arasında çok fark olmadığında, negatif review pozitif reviewden fazla olmasına rağmen, metodumuz pozitif bir etkiye sahip oluyor. Örneğin ortalama rating 7,2 olduğunda ve negatif, pozitif review sayıları eşit olduğunda, sonucun 6,65 olduğunu görüyoruz. Bunun nedeni 0 ila 7,2 arasındaki mesafenin 7,2 ila 10 arasındaki mesafeden fazla olması. Bu yüzden hesaplanan değer daha negatif bir etki yaratıyor. Ama genellikle uç kısımlara yakın ratinge sahip içerikler için pozitif ve negatif review sayıları birbirine yakın olmadığı için, bu sorun sistemimizi çokta kötü etkilemeyebilir. Dahası, genellikle içerikler reviewe kıyasla daha çok rating aldığı için, yukardaki testlerdede sayılar buna göre verildi ve haliyle reviewlerin etkisi çok fazla değil. Bu etki farklı bir parametre ekleyerek artırılabilirdi. (Örneğin her bir pozitif review için hesaplanan rating değerine sahip 10 adet rating ekle şeklinde. Şu anda biz her bir review için 1 adet rating ekliyoruz.)

Uygulama

Artık metodumuzun nasıl çalıştığını ve ne tür sonuçlar verdiğini gördüğümüze göre, rating_extactor.py dosyasını açalım ve RatingExtractor sınıfına aşağıda metodu ekleyelim:

    @staticmethod
def get_rating_with_count_and_reviews(r, rc, pf, bf):
if r > 10 or r < 0:
return None
else:
positive_diff = (10 - r) / 2
positive_rating = r + positive_diff
negative_diff = r / 2
negative_rating = r - negative_diff
updated_rating = ((r * rc) + (pf * positive_rating) + (bf * negative_rating)) / (rc + pf + bf)return RatingExtractor.get_rating_weight_with_quantity(updated_rating,rc,1000000,10)

Metod aşağıdaki şekilde çalışacak:

  • r (rating), rc (rating sayısı), pf (pozitif review sayısı) ve bf (negatif review sayısı parametrelerini alıyor.
  • Pozitif reviewler için dönüştürülen rating değerini hesaplıyor.
  • Negatif reviewler için dönüştürülen rating değerini hesaplıyor.
  • Güncellenen rating değerini, eski ortalama rating ve yeni dönüştürülen ratingleri hesaba katarak hesaplıyor.
  • Daha önceki bölümde geliştirilen bir metodu, güncellenen rating değeri, rating sayısı, T = 1.000.000 (eşik) ve Q = 100 (rating önem parametresi) parametreleriyle çağırarak sonucu rating katkısı olarak dönüyor.

RecommenderEngine sınıfına yeni metod ekleme

Şimdi, recommender_engine.py dosyasını açalım ve aşağıdaki metodu RecommenderEngine sınıfına ekleyelim. Bu metod daha önce geliştirdiğimiz metodlara benzemesine rağmen, şimdi pozitif review ve negatif review sayılarını da kullanacağız.

get_recommendations_include_rating_count_threshold_positive_negative_reviews metodu

Metod aşağıdaki gibi çalışacak:

  • Keywords parametresini alıyor ve aşağıdaki adımları şehirler için uyguluyor
  • CS skorunu hesaplıyor
  • rating, rating count, positive review count ve negative review count parametrelerini kullanarak, rating katkı ağırlığı değerini hesaplıyor. Bu sefer T ve Q parametreleri direk RatingExtractor sınıfındaki yeni metodda kullanıldı.
  • calculate_final_score metodunu (daha önceki bölümlerde geliştirildi) CS skoru ve rating ağırlığı parametreleriyle çağırarak son skoru hesaplıyor.
  • En yüksek skora sahip 5 şehri JSON a çevirerek dönüyor.

Request

request.py dosyasına, her üç kategori için öneri alacak requestler ekleyeceğiz.

Öncelikle, RecommenderEngine sınıfındaki yeni metodla önerileri alacak bir metod yazalım:

def get_recommendations_include_rating_count_threshold_positive_negative_reviews(keywords):
return RecommenderEngine.get_recommendations_include_rating_count_threshold_positive_negative_reviews(keywords)

Şimdi yeni metodu kullanarak her 3 kategori için önerileri alalım ve ekrana yazdıralım:

# Version 4 requests are below:top_5_cultural_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(culture_keywords)
city_names_for_cultural_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_cultural_with_rating_count_threshold_reviews)
print(city_names_for_cultural_rating_count_threshold_reviews)
print("#################")
top_5_summer_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(beach_n_sun_keywords)
city_names_for_summer_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_summer_with_rating_count_threshold_reviews)
print(city_names_for_summer_rating_count_threshold_reviews)
print("#################")
top_5_party_with_rating_count_threshold_reviews = get_recommendations_include_rating_count_threshold_positive_negative_reviews(nightlife_keywords)
city_names_for_party_rating_count_threshold_reviews = get_top_5_city_names_out_of_json(top_5_party_with_rating_count_threshold_reviews)
print(city_names_for_party_rating_count_threshold_reviews)
print("#################")

Yukardaki kod, her 3 kategori içinde sonuçları alacak ve ekrana yazdıracak. request.py dosyasını çalıştırarak aldığınız sonuçları görebilir ve inceleyebilirsiniz. Yazımızın başında metodumuz ve alınabilecek sonuçlar detaylı olarak incelendiği için bu bölümde kod sonucu inceleme kısmını pas geçeceğim. Yalnızca Kültür, Sanat ve Tarih kategorisi için alınan sonuçlar aşağıda verilmiştir:

[('Athens', 0.2622560540924768), 
('Milan', 0.2040068651858985),
('Rome', 0.16752794267650856),
('Stockholm', 0.14984473241175314),
('Barcelona', 0.14831614523091158)]

Ama tüm kategoriler için alınan sonuçları detaylı bir şekilde incelemenizi öneririm. Veri setini inceleyerek 3. versiyondaki sonuçlarla bu versiyonda aldığımız sonuçları kıyaslamanız kesinlikle faydalı olacaktır. Nasıl bir fark görüyorsunuz ve sizce neden? Eğer bir sorunuz olursa bana yorumlarda sorabilirsiniz :)

Sonuç

Bu versiyonda Öneri Sistemlerinde farklı türden feedbackleri birbirine dönüştürerek birlikte kullanmayı gördük. Farklı yöntemlerin nasıl negatif etkileri olabileceğini, ve geliştirdiğimiz sisteminde bazı durumlarda nasıl istenmeyen sonuçlar doğurabildiğini inceledik. Siz olsaydınız nasıl bir formülle bu sorunları atlatmaya çalışırdınız? Bunu düşünmeniz faydalı olacaktır.

Bu versiyonla birlikte, Öneri Sistemi (Recommender System) uygulamamızın sonuna geldik. Bu yazımızda, kullanıcı hakkında hemen hemen hiçbir şey bilmediğimiz durumlarda (cold start problem), kullanıcıların sadece belirli bir kategori seçmesini isteyerek farklı tekniklerle öneri yapan bir sistem geliştirdik. Umarım sonuna kadar takip edip bu yazıdan memnun kalmışsınızdır. Bu yazıda geliştirilen formül ve teknikler benim kendi fikirlerim olduğu için mükemmel değiller, buna yazılarımızdada zaman zaman şahit olduk veya değindik. Bu yüzden eğer sistemi dahada geliştirebileceğimizi düşündüğünüz alanlar varsa, lütfen yorum olarak belirtin :)

Projemizin son halini buradan indirebilirsiniz.

Hoşçakalın.

Ekstra

Veri setimizde olan bazı featureların neden kullanılmadığını merak ediyor olabilirsiniz. Birinci bölümün başında belirttiğim gibi, bu serimizde geliştirilen teknikler benim master projemin bir parçası. Master projemin bir diğer parçasıda Flutter kullanarak cross platform mobil uygulama geliştirmekti. Bazı featureları orada kullanmıştım. Bahsettiğim uygulamanın ekran görüntülerini aşağıda görebilirsiniz:

Mobil uygulamadan resimler

Eğer bu serimizde geliştirdiğimiz sistem için Flutter kullanarak UI geliştirmek ilginizi çektiyse, lütfen beni haberdar edin. Belki başka bir yazıda birlikte uygulama geliştirebiliriz :)

Kendinize iyi bakın!

--

--

Emre Havan

Senior iOS Software Engineer — Interested in Compilers, ML and recommender systems — https://github.com/emrepun