2017-01-10 24 views
7

Przewiduję oceny pomiędzy procesami, które wsadowo trenują model. Używam podejścia przedstawionego tutaj: ALS model - how to generate full_u * v^t * v?Model ALS - przewidywany full_u * v^t * v oceny są bardzo wysokie

! rm -rf ml-1m.zip ml-1m 
! wget --quiet http://files.grouplens.org/datasets/movielens/ml-1m.zip 
! unzip ml-1m.zip 
! mv ml-1m/ratings.dat . 

from pyspark.mllib.recommendation import Rating 

ratingsRDD = sc.textFile('ratings.dat') \ 
       .map(lambda l: l.split("::")) \ 
       .map(lambda p: Rating(
            user = int(p[0]), 
            product = int(p[1]), 
            rating = float(p[2]), 
           )).cache() 

from pyspark.mllib.recommendation import ALS 

rank = 50 
numIterations = 20 
lambdaParam = 0.1 
model = ALS.train(ratingsRDD, rank, numIterations, lambdaParam) 

Potem wyodrębnić cechy produktu ...

import json 
import numpy as np 

pf = model.productFeatures() 

pf_vals = pf.sortByKey().values().collect() 
pf_keys = pf.sortByKey().keys().collect() 

Vt = np.matrix(np.asarray(pf_vals)) 

full_u = np.zeros(len(pf_keys)) 

def set_rating(pf_keys, full_u, key, val): 
    try: 
     idx = pf_keys.index(key) 
     full_u.itemset(idx, val) 
    except: 
     pass 

set_rating(pf_keys, full_u, 260, 9), # Star Wars (1977) 
set_rating(pf_keys, full_u, 1, 8), # Toy Story (1995) 
set_rating(pf_keys, full_u, 16, 7), # Casino (1995) 
set_rating(pf_keys, full_u, 25, 8), # Leaving Las Vegas (1995) 
set_rating(pf_keys, full_u, 32, 9), # Twelve Monkeys (a.k.a. 12 Monkeys) (1995) 
set_rating(pf_keys, full_u, 335, 4), # Flintstones, The (1994) 
set_rating(pf_keys, full_u, 379, 3), # Timecop (1994) 
set_rating(pf_keys, full_u, 296, 7), # Pulp Fiction (1994) 
set_rating(pf_keys, full_u, 858, 10), # Godfather, The (1972) 
set_rating(pf_keys, full_u, 50, 8) # Usual Suspects, The (1995) 

recommendations = full_u*Vt*Vt.T 

top_ten_ratings = list(np.sort(recommendations)[:,-10:].flat) 

print("predicted rating value", top_ten_ratings) 

top_ten_recommended_product_ids = np.where(recommendations >= np.sort(recommendations)[:,-10:].min())[1] 
top_ten_recommended_product_ids = list(np.array(top_ten_recommended_product_ids)) 

print("predict rating prod_id", top_ten_recommended_product_ids) 

Jednak prognozowane wskaźniki wydają się zbyt wysokie: Komunikat ten

('predicted rating value', [313.67320347694897, 315.30874327316576, 317.1563289268388, 317.45475214423948, 318.19788673744563, 319.93044594688428, 323.92448427140653, 324.12553531632761, 325.41052886977582, 327.12199687047649]) 
('predict rating prod_id', [49, 287, 309, 558, 744, 802, 1839, 2117, 2698, 3111]) 

być niepoprawnym. Wszelkie wskazówki są mile widziane.

+1

Uzyskałem dobre wyniki, używając tego, ale było to z niejawnym sprzężeniem zwrotnym, oceny: 0 dla negatywnej lub nieznanej i 1 dla pozytywnej. Otrzymałem prognozę między 0 a 1 i używałem rangi jako metryki, tj. Nie zwracając uwagi na wyniki. –

+0

Ah, interesujące. Nie analizuję jeszcze ukrytych informacji zwrotnych. Jeśli umieścisz swój komentarz jako odpowiedź, otrzymasz domyślną nagrodę, jeśli nikt inny nie odpowie;) –

+0

@ yoh.lej Ah, to wyjaśnia, dlaczego dostałem takie zawyżone oceny jak Chris! Zakładamy zatem, że oceny są wtedy binarne. Yohan, czy mógłbyś krótko wyjaśnić, na czym opiera się ta formuła? Próbowałem googling dla podobieństwa i nie widziałem go. Do czego obliczamy podobieństwo? Zaintrygowany, ponieważ obecnie biorę klasę algebry liniowej. Logicznie rzecz biorąc, wydaje się, że chcielibyśmy ustalić, który z istniejących użytkowników jest dla tego użytkownika najbardziej podobny, i wykorzystać ich czynniki do przewidywania ocen - czy to podejście jest bardziej wyrafinowane? Dzięki! (Chris - sprawdź ALS.trainImplicit) – ScottEdwards2000

Odpowiedz

5

Myślę, że wspomniane podejście zadziała, jeśli dbasz tylko o ranking filmów. Jeśli chcesz uzyskać rzeczywistą ocenę, wydaje się, że jest coś pod względem wymiaru/skalowania.

Pomysł polega na odgadnięciu ukrytej reprezentacji nowego użytkownika. Normalnie, dla użytkownika już w fazie faktoryzacji, użytkownik i, ma swoją ukrytą reprezentację u_i (i-ty wiersz w model.userFeatures()) i dostajesz jego ocenę dla danego filmu (filmu j) przy użyciu model.predict, który zasadniczo mnoży u_i przez utajoną reprezentację produkt v_j. możesz uzyskać wszystkie przewidywane oceny naraz, jeśli pomnożysz się z całym v: u_i*v.

Dla nowego użytkownika musisz odgadnąć, jaka jest jego ukryta reprezentacja u_new z full_u_new. Zasadniczo potrzebujesz 50 współczynników, które reprezentują nowe powinowactwo użytkownika do każdego z ukrytych czynników produktu. Dla uproszczenia i ponieważ to wystarczyło dla mojego domyślnego zastosowania, po prostu użyłem produktu kropki, zasadniczo rzutując nowego użytkownika na czynnik ukryty produktu: full_u_new*V^t daje 50 współczynników, coeff jest tym, jak wygląda twój nowy użytkownik czynnik latentny produktu. i działa szczególnie dobrze z ukrytą informacją zwrotną. Tak więc, za pomocą produktu dot da to, ale nie będzie skalowane i wyjaśnia wysokie wyniki, które widzisz. Aby uzyskać użyteczne wyniki trzeba bardziej precyzyjnie skalowane u_new, myślę, że można dostać się, że za pomocą podobieństwa cosinus, jak oni [tutaj] https://github.com/apache/incubator-predictionio/blob/release/0.10.0/examples/scala-parallel-recommendation/custom-query/src/main/scala/ALSAlgorithm.scala

Podejście wspomniał @ ScottEdwards2000 w komentarzu jest ciekawa, ale raczej różne. Można nawet znaleźć najbardziej podobnego użytkownika (użytkowników) w swoim zestawie szkoleniowym. Jeśli jest ich więcej niż jeden, możesz uzyskać średnią. Nie sądzę, że byłoby to zbyt złe, ale jest to naprawdę inne podejście i potrzebujesz pełnej matrycy oceny (aby znaleźć najbardziej podobnych użytkowników). Uzyskanie jednego bliskiego użytkownika powinno zdecydowanie rozwiązać problem skalowania. Jeśli uda Ci się oboje podejść do pracy, możesz porównać wyniki!