Recommender System Genel Bakış (Part 3: Matrix Factorization)
Yazı serisinin ilk kısmında popülerliğe ve içeriğe göre öneri modellerine değindik. 2. kısımda Collaborative Filtering ve Hybrid modelleri incelemiştik. Bu kısımda da Matrix Factorization konusuna değineceğiz.
Matrix Factorization, recommendation sistemlerinde kullanılan bir collaborative filtering çeşididir. Matrix Factorization da User — Item Matrisini daha küçük boyutlu ve içerisinde latent featurelar barındıran 2 matrise ayırırız.
Burada temelde yapılan iş matematik de kullandığımız çarpanlara ayırma işlemidir.
Örneğin:
10 sayısını 5 * 2 şeklinde çarpanlarına ayırabiliriz. Benzer işlemi User-Item matrisinde de yapacağız.
R_hat(predicted rating) = W * U.T -> Rating matrisini W(User) ve U(Item) olarak iki matrise ayırabiliriz.
Neden Kullanırız?
Rating matrisini memorye store etmek çok fazla yer kaplayacaktır. W ve U matrisleri çok daha az yer kaplamasını bekleriz. Örneğin:
Eğer 100 bin kullanıcı ve 10 bin filmimiz olsaydı. N = 100.000 ve M = 10.000 olurdu.
N*M = 1.000.000.000 (1 milyar) değeri tutmamız gerekecek.
Rating tablosunda sadece 10 milyon oy olduğunu düşünelim.
Burada sparsity çok yüksek olacaktır.
10.000.000/1.000.000.000 = 0.01 kullanılan alan.
Latent featureları göstermek için bir K değeri belirleriz. Bu K değeri genellikle 10–50 arasında bir değer alır. W(NxK) ve U(MxK) şeklinde gösteririlir.
K = 10 için : NK + MK = 1 milyon + 100 bin = 1.100.000 alan kullanılacak. Bu şeklinde 1 milyar değer yerine sadece 1 milyon değeri hafızada tutacağız.
Bir kullanıcının herhangi bir filme kaç puan vereceğini öğrenmek için. Örn user i movie j için:
rij = wi.T*uj şeklinde hesap yaparız.
Bir Örnek İle İnceleyelim
Her K değerine bir feature diyelim. K=5 için bu özellikler:
Aksiyon, Komedi, Romantik, Korku ve Animasyon olsun.
wi(1) user i aksiyon filmlerini ne kadar seviyor.
uj(1) movie j ne kadar aksiyon barındırıyor.
Burada wi.T*uj işlemi bize user i ile movie j arasındaki korelasyonun büyüklüğünü verir.
Örneğin:
wi = (1,0.8,-1,0.1,1) uj = (1,1.5,-1.3,0,1.2)
result = 1 * 1 + 0.8 * 1.5 + 1 * 1.3 … = 4.7 sonucunu alırız. Burada user i movie j ile korelasyonu yüksek olduğu için yüksek bir puan aldı. User i nin film zevkini vektör ile ifade ettik ve filmin içeriğinin de user i ile uyumlu olduğunu bu şekilde tespit ettik diyebiliriz. User i’a movie j yi önerebiliriz.
Özellikler
Yukarıdaki örnekte featureları biz belirledik. Birinci özellik aksiyon 2. özellik komedi şeklinde bunu her film için yapmamız mümkün değildir. Bu sebeple bu özellikler random olarak başlatılır modeli eğiterek güncellenir. Bu özelliklere aynı zamanda latent features denir.
Eğitim
R_hat matriksinin ne kadar doğru olduğunu nasıl tespit ederiz.
Buradaki problemimiz bir regresyon problemi olduğu için bunu Squared Error ile belirleyebiliriz.
J = sum(rij-r_hatij)² şeklinde hesaplarız. r_hat = wi.T * uj
J = sum(r — r_hat)² = sum(r-wi.T * j-uj)²
W için :
dJ/dwi = 2 * sum(rij — wi.T * uj)(-uj) = 0
sum(uj.T * wi) * uj = sum(rij * uj) -> sum(uj * uj.T * wi) = sum(rij * uj)
(sum(uj * uj.T)) * wi = sum(rij * uj)
wi = (sum(uj * uj.T)^-1 * sum(rij * uj) x = np.linalg.solve(A,b) -> numpy linalg.solve metodu ile wi değerini hesaplayacağız.
Aynı işlemi U içinde yapacağız.
Burada regularization ve bias değerlerini de eklersen son formül aşağıdaki gibi olacak.
wi = (sum(uj * uj.T)^-1 * sum(rij -bi-cj-mu)*uj
uj = (sum(wi * wi.T)^-1 * sum(rij -bi-cj-mu)*wi
Model Eğitimi ve Çıktılar
Yandaki örnekte 10 kullanıcı ve 4 film için bir Rating verisi bulunuyor.
Burada kullanıcıların oy vermedikleri ve bizimde tahmin etmek istediğimiz filmler 0 olarak belirttik.
N :Kullanıcı Sayısı M : Film Sayısı K değeri latent feature boyutu. b değeri userlar için bias c ise filmler için bias değeridir. mu değeri ortalama rating tutmak için kullanılıyor.
Random olarak NxK boyutunda bir user matrisi ve MxK boyutunda bir movie matrisi oluşturuyoruz. Bu matrisler içerisinde eğitim sonucu güncellenecek latent featurelarımız bulunuyor.
Aşağıdaki gibi eğitimi 25000 adım kadar yapacağız. Burada öncellikle bir matris ve bir vektör oluşturuyoruz.
Aşağıdaki formülde koyu ile belirttiğim (sum(uj * uj.T)^-1 ) kısmın hesaplanması için np.outer metodunu kullanıyoruz.
wi = (sum(uj * uj.T)^-1 )* sum(rij -bi-cj-mu)*uj
Aşağıdaki formülde ikinci kısımda belirtilen değerleri de toplayıp vector değişkenine ekliyoruz.
wi = (sum(uj * uj.T)^-1 )* sum(rij -bi-cj-mu)*uj
wi = np.linalg.solve(sum(uj * uj.T)^-1 ), sum(rij -bi-cj-mu)*uj)
metodu ile yukarıdaki denklemi çözüp W[i] değerini hesaplamış oluyoruz. Bu W[i] değeri 1. kullanıcı için
Aynı işlemi U içinde yapıyoruz.
R_hat hesaplamak için eğitimin sonunda elde eğitilmiş parametreler ile W[i].dot(U[j]) + b[i] + c[j] + mu değerini hesaplıyoruz.
Gradient descent ile hesapladığımız R ve R_hat değerleri aşağıdaki gibidir.
Aşağıdaki sonuçta 0 olan değerlerin tahminlerini görüyorsunuz. Bu sonuçlar 1. ve 4. sütundaki filmlerin benzer aynı zamanda 2. ve 3. sütundaki filmlerin benzer olduğunu düşünerek veriyi oluşturmuştum. Aşağıda da beklediğimiz gibi kullanıcının yönelimine göre oldukça başarılı tahminler yapmış görünüyoruz.