Sistemi di raccomandazione : User-based Collaborative Filtering using N Nearest Neighbors

Ashay Pathak
Ashay Pathak

Follow

Feb 25, 2019 – 9 min read

Ashay Pathak, Chatana Mandava, Ritesh Patel

Collaborative Filtering è una tecnica ampiamente utilizzata nei sistemi di raccomandazione ed è un’area di ricerca in rapido progresso. I due metodi più comunemente usati sono basati sulla memoria e sul modello.

In questo post, ci concentreremo solo su (User-Based Collaborative Filtering) UB-CF che è un metodo basato sulla memoria. L’idea principale dietro UB-CF è che le persone con caratteristiche simili condividono gusti simili. Per esempio, se siete interessati a raccomandare un film al nostro amico Bob, supponiamo che Bob ed io abbiamo visto molti film insieme e li abbiamo valutati quasi allo stesso modo. Ha senso pensare che anche in futuro continueranno a piacerci film simili e usare questa metrica di somiglianza per raccomandare i film.

Proviamo a implementare UB-CF e a generare una lista di film che il nostro amico Bob, alias utente attivo, potrebbe essere interessato a vedere. La motivazione dietro la scrittura di questo post è di immergersi profondamente nell’algoritmo e capire come funziona effettivamente UB-CF. La maggior parte del contenuto di questo post è ispirato da un corso su Coursera.

User-User Collaborative Filtering

Il metodo identifica gli utenti che sono simili all’utente interrogato e stima il rating desiderato come media ponderata dei rating di questi utenti simili.

Collaborative Filtering : source here

Faremmo le raccomandazioni su MovieLens Dataset. Il linguaggio di programmazione utilizzato è python e il lavoro di analisi dei dati è fatto principalmente utilizzando la libreria pandas. L’IDE utilizzato è jupyter notebook.

Prima di iniziare vorrei dare la lista delle librerie utilizzate:

  1. Pandas
  2. Numpy
  3. sklearn

Perciò andiamo avanti e capiamo i concetti dietro le raccomandazioni. Ho allegato alcuni frammenti di codice e output nel blog per una migliore comprensione. L’intero file ipynb è allegato alla fine del blog.

Funzione di punteggio

È facile inventare una funzione per il filtraggio collaborativo non personalizzato (cioè non consideriamo i gusti, le antipatie e le valutazioni dell’utente attivo nel passato) che restituisce un punteggio prendendo l’utente u e l’oggetto i come parametri di input. La funzione restituisce un punteggio che quantifica quanto fortemente all’utente u piace/preferisce l’oggetto i.

Quindi questo viene fatto di solito usando le valutazioni di altre persone simili all’utente. Tutto questo sarà discusso in dettaglio più tardi. Per ora la formula che ho usato è,

funzione punteggio

dove ‘s’ è il punteggio previsto, ‘u’ è l’utente, ‘i’ è l’oggetto, ‘r’ è la valutazione data dall’utente e ‘w’ è il peso.

In questo caso il nostro punteggio è uguale alla somma delle valutazioni che ogni utente ha dato a quella voce sottraendo la valutazione media di quell’utente moltiplicata per un certo peso che è di quanto questo utente è simile o si suppone che contribuisca alle previsioni degli altri utenti. Questo è il peso tra l’utente u e v. Il punteggio varia da 0 a 1 dove 0 è basso e 1 è alto. Tutto sembra perfetto, allora perché abbiamo sottratto le valutazioni medie da ogni valutazione degli utenti e perché abbiamo usato la media ponderata invece della media semplice?

Il problema è con i tipi di utenti che stiamo gestendo. Inizia con il fatto che le persone valutano spesso su scale molto diverse. Io posso essere un utente positivo e ottimista, dove valuterò il film che mi è piaciuto come 4 su 5, ma qualche altro utente che è meno ottimista o ha degli standard elevati può valutare il suo film preferito come 2 su 5. Qui il suo 2 è il mio 4. Qui il suo 2 è il mio 4. Le modifiche per renderlo migliore sono, possiamo aumentare l’efficienza di questo algoritmo se normalizziamo la valutazione dell’utente. Un modo per farlo è dire che calcoleremo s(u,i) cioè il punteggio come la valutazione media che l’utente dà ad ogni elemento più una certa deviazione e la deviazione sarà quanto questo elemento è migliore o peggiore della media.

Ho usato la similarità del coseno per calcolare il peso dato nella formula sopra. Ho anche usato la nozione di vicinato che sarà discussa in questo blog man mano che andiamo avanti.

Per normalizzare i dati nel modo di cui sopra, è necessaria una certa analisi dei dati in pandas. Potete ottenere l’intero codice alla fine. Per il blog, mi concentrerò sui concetti importanti.

import pandas as pdmovies = pd.read_csv("movies.csv",encoding="Latin1")
Ratings = pd.read_csv("ratings.csv")
Tags = pd.read_csv("tags.csv",encoding="Latin1")Mean = Ratings.groupby(by="userId",as_index=False).mean()
Rating_avg = pd.merge(Ratings,Mean,on='userId')
Rating_avg=Rating_avg-Rating_avg
Rating_avg.head()

Valutazione normalizzata

Ora abbiamo finito di calcolare la valutazione normalizzata per un utente. I dati di cui sopra saranno utilizzati per calcolare il punteggio finale per l’utente in seguito.

Da qui ci concentreremo ora su alcuni importanti concetti relativi ai sistemi di raccomandazione.

Similitudine coseno

Per la formula di cui sopra abbiamo bisogno di trovare gli utenti che hanno pensieri simili. Questo sembra molto interessante per trovare un utente che ha simpatie e antipatie simili. Ma la domanda è come facciamo a trovare la somiglianza?

Per rispondere a questo, useremo la Similarità Coseno e vedremo quanto sono simili gli utenti. Di solito si calcola sulle valutazioni che entrambi gli utenti hanno dato in passato.

Nel nostro esempio, ho usato la funzione cosine_similarity di sklearn per calcolare la similarità. Ma prima di questo dobbiamo eseguire un po’ di pre-elaborazione e pulire i dati.

from sklearn.metrics.pairwise import cosine_similarityfinal=pd.pivot_table(Rating_avg,values='adg_rating',index='userId',columns='movieId')

tabella pivot

Questa contiene alcuni valori NaN poiché ogni utente non ha visto tutti i film ed è la ragione per cui questo tipo di matrice è chiamata matrice rada. Metodi come la fattorizzazione della matrice sono usati per trattare questa sparsità ma non ci concentreremo su di essa in questo blog. Il prossimo passo e uno dei passi importanti è quello di sostituire questi valori NaN.

Ci sono due metodi comunemente usati per questo:

  1. Utilizzare la media dell’utente sulla riga.
  2. Utilizzare la media del film sulla colonna.

Ho usato entrambi i metodi e potete ottenerli nel codice qui sotto. Ma per spiegare userei il metodo della media del film.

# Replacing NaN by Movie Average
final_movie = final.fillna(final.mean(axis=0))

Riposizionare i valori NaN con la media del film

Ora, il prossimo passo è calcolare la similarità tra gli utenti.

# user similarity on replacing NAN by item(movie) avg
cosine = cosine_similarity(final_movie)
np.fill_diagonal(cosine, 0 )
similarity_with_movie =pd.DataFrame(cosine,index=final_movie.index)
similarity_with_movie.columns=final_user.index
similarity_with_movie.head()

Similitudine coseno utente

Controlliamo se ciò che abbiamo calcolato ha davvero senso!

a = get_user_similar_movies(370,86309)
a = a.loc]
a.head()

film simili

Dall’immagine sopra possiamo vedere che la somiglianza che abbiamo generato è vera poiché entrambi gli utenti dati (370,86309) hanno quasi gli stessi voti e gradimento.

Allora abbiamo finito di calcolare le somiglianze tra gli utenti ma non sono ancora contento. Discuterò il motivo nel prossimo passo.

Neighborhood for User (K)

Così da sopra possiamo vedere che abbiamo calcolato le similarità per tutti gli utenti. Ma essendo uno studente di Big Data, la complessità del problema mi guida sempre. Con questo voglio dire che il sistema di raccomandazione lavora con dati enormi e quindi diventa molto importante mantenere e catturare solo i punti salienti importanti e necessari dai dati.

Per spiegare questo usando il nostro esempio di sistema di raccomandazione di film, la matrice che abbiamo ottenuto sopra è (862*862), poiché ci sono 862 utenti unici nei dati. Questo numero è ancora piccolo rispetto ai dati su cui il sistema originale dovrebbe lavorare. Pensiamo ad Amazon. Avrebbe più di milioni di utenti nel suo database e così, mentre si calcola il punteggio per qualsiasi elemento, non sarebbe una buona soluzione o metodo per guardare tutti gli altri utenti per tutto il tempo. Quindi, per superare questo, generiamo una nozione di vicinato. Questo include solo l’insieme di (K) utenti simili per un particolare utente.

Ora facciamo ulteriori passi per implementare l’idea. Nel nostro esempio ho preso il valore di k come 30. Quindi avremmo 30 vicini più vicini per tutti gli utenti.

Ho usato la mia funzione personalizzata find_n_neighbours che prende la matrice di similarità e il valore di n come input e restituisce gli n vicini più vicini per tutti gli utenti. Potete trovare il codice nel notebook dato alla fine del blog.

# top 30 neighbours for each user
sim_user_30_m = find_n_neighbours(similarity_with_movie,30)
sim_user_30_m.head()

top 30 vicini per gli utenti

Quindi ora se pensate abbiamo seriamente ridotto il numero di calcoli inutili. Ora siamo pronti a calcolare il punteggio per un elemento.

Generazione del punteggio finale S(u,i)

Wow! abbiamo finito il processo. So che siamo passati attraverso alcune cose molto tecniche, ma il tempo che abbiamo speso vale la pena, perché abbiamo raggiunto l’ultimo passo.

Qui proveremo a predire il punteggio per il film che l’utente dato non ha visto.

score = User_item_score(320,7371)
print(score)

predetto punteggio

Quindi il nostro sistema ha predetto il punteggio di 4,25 che è davvero buono. Penso che all’utente (370) potrebbe piacere il film con id (7371).

Ora diamo un tocco finale al nostro sistema. Penso che la maggior parte di noi avrebbe usato Netflix o Hotstar. Quindi, quando apriamo l’app, essa mostra l’elemento che si fa come.

Io rimango sempre affascinato dalla raccomandazione in quanto risultano essere i film che mi piacciono. Tutto questo avviene attraverso il sistema di raccomandazione stesso. Ora faremo lo stesso e cercheremo di predire i primi 5 film che possono piacere a un dato utente.

La logica non è così difficile. Abbiamo già generato il punteggio per un elemento. Allo stesso modo possiamo generare il punteggio per gli altri elementi con lo stesso utente.

Ma, ora, sempre tenendo in considerazione i Big Data, ha senso generare il punteggio per tutti gli altri elementi?

Credo di no!!!

Consideriamo l’utente (U) e l’utente (K). Ora supponiamo che K non sia nelle vicinanze di U, è possibile che all’utente U piaccia un film che K ha visto e valutato. Per lo più No.

Credo che tu abbia capito il trucco. Sì, siamo solo interessati a calcolare i punteggi per gli elementi che gli utenti vicini hanno visto.

Abbiamo davvero successo. Abbiamo ridotto il calcolo da 2500 a N (dove N è l’insieme dei film che sono piaciuti al mio vicino) e che è molto meno di 2500.

Quindi, finalmente, raccomandiamo i film.

User_item_score1 è la mia funzione personalizzata che usa la nostra discussione precedente per calcolare le previsioni

user = int(input("Enter the user id to whom you want to recommend : "))
predicted_movies = User_item_score1(user)
print(" ")
print("The Recommendations for User Id : ",user)
print(" ")
for i in predicted_movies:
print(i)

Alla fine!!!! Ce l’abbiamo fatta. Abbiamo il nostro sistema di raccomandazione.

La rappresentazione del codice qui sotto potrebbe non essere molto facile da leggere, quindi per favore andate sul mio repository GitHub per accedere al codice.

I dataset richiesti possono essere ottenuti da qui.

Spero che il blog vi sia piaciuto. Per qualsiasi domanda potete mandarmi una mail. Restate sintonizzati per altri blog dato che questa è una delle mie aree di interesse e sicuramente pubblicherò qualcosa di nuovo.

Grazie!!!

Lascia un commento

Il tuo indirizzo email non sarà pubblicato.