Recomandarea sistemelor : User-based Collaborative Filtering using N Nearest Neighbors

Ashay Pathak
Ashay Pathak

Follow

25 februarie, 2019 – 9 min citește

Ashay Pathak, Chatana Mandava, Ritesh Patel

Filtrarea colaborativă este o tehnică care este utilizată pe scară largă în sistemele de recomandare și este un domeniu de cercetare care avansează rapid. Cele două metode cel mai frecvent utilizate sunt cele bazate pe memorie și cele bazate pe modele.

În acest post, ne vom concentra doar pe (User-Based Collaborative Filtering) UB-CF, care este o metodă bazată pe memorie. Ideea principală din spatele UB-CF este că persoanele cu caracteristici similare împărtășesc gusturi similare. De exemplu, dacă sunteți interesați să îi recomandați un film prietenului nostru Bob, să presupunem că Bob și cu mine am văzut multe filme împreună și le-am evaluat aproape identic. Este logic să ne gândim că și în viitor vom continua să ne placă filme similare și să folosim această metrică de similaritate pentru a recomanda filme.

Să încercăm să implementăm UB-CF și să generăm o listă de filme pe care prietenul nostru Bob, alias utilizatorul activ, ar putea fi interesat să le vadă. Motivația din spatele scrierii acestei postări este de a pătrunde adânc în algoritm și de a înțelege cum funcționează de fapt UB-CF. Cea mai mare parte a conținutului acestei postări este inspirată de un curs de pe Coursera.

User-User Collaborative Filtering

Metoda identifică utilizatorii care sunt similari cu utilizatorul interogat și estimează ratingul dorit ca fiind media ponderată a ratingurilor acestor utilizatori similari.

Filtrare colaborativă : sursa aici

Am face recomandări pe setul de date MovieLens. Limbajul de programare utilizat este python, iar activitatea de analiză a datelor se realizează în principal cu ajutorul bibliotecii pandas. IDE-ul utilizat este jupyter notebook.

Acum, înainte de a începe, aș dori să dau lista bibliotecilor utilizate :

  1. Pandas
  2. Numpy
  3. sklearn

Acum să mergem mai departe și să înțelegem conceptele din spatele recomandărilor. Am atașat câteva fragmente de cod și rezultate pe blog pentru o mai bună înțelegere. Întregul fișier ipynb este atașat la sfârșitul blogului.

Funcția de scor

Este ușor să venim cu o funcție pentru filtrarea colaborativă nepersonalizată (adică nu luăm în considerare plăcerile, displacerile și evaluările din trecut ale utilizatorului activ) care returnează un scor luând ca parametri de intrare utilizatorul u și elementul i. Funcția generează un scor care cuantifică cât de mult îi place/preferă un utilizator u elementul i.

De obicei, acest lucru se face folosind evaluările altor persoane similare cu utilizatorul. Toate acestea vor fi discutate în detaliu mai târziu. Deocamdată, formula pe care am folosit-o este,

funcția de scor

Unde “s” este scorul prezis, “u” este utilizatorul, “i” este elementul, “r” este ratingul acordat de utilizator și “w” este ponderea.

În acest caz, scorul nostru este egal cu suma evaluărilor pe care fiecare utilizator le-a dat acelui element, scăzând evaluarea medie a acelui utilizator înmulțită cu o anumită pondere care reprezintă cât de mult acest utilizator este similar sau se presupune că ar trebui să contribuie la predicțiile celorlalți utilizatori. Aceasta este ponderea dintre utilizatorul u și v. Punctajul variază între 0 și 1, unde 0 este mic și 1 este mare. Totul pare perfect, dar atunci de ce am scăzut ratingurile medii din ratingul fiecărui utilizator și de ce am folosit media ponderată în loc de media simplă?

Problema este legată de tipurile de utilizatori pe care le gestionăm. Începe cu faptul că oamenii evaluează adesea pe scale foarte diferite. Eu pot fi un utilizator pozitiv și optimist, în cazul în care voi evalua filmul care mi-a plăcut cu 4 din 5, dar un alt utilizator care este mai puțin optimist sau are niște standarde ridicate poate evalua filmul său preferat cu 2 din 5. În acest caz, 2 al lui este 4 al meu. Pentru a-l îmbunătăți, putem crește eficiența acestui algoritm dacă normalizăm evaluarea utilizatorului. O modalitate de a face acest lucru este să spunem că vom calcula s(u,i), adică scorul ca fiind ratingul mediu pe care utilizatorul îl acordă fiecărui element plus o anumită abatere, iar abaterea va reprezenta cât de mult acest element este mai bun sau mai rău decât media.

Am folosit similitudinea cosinusului pentru a calcula ponderea dată în formula de mai sus. Am folosit, de asemenea, noțiunea de vecinătate care va fi discutată în acest blog pe măsură ce vom merge mai departe.

Pentru a normaliza datele în modul de mai sus, este necesară o anumită analiză a datelor în pandas. Puteți obține întregul cod la sfârșit. Pentru blog, mă voi concentra pe conceptele importante.

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()

Normalized ratings

Acum am terminat de calculat ratingul normalizat pentru un utilizator. Datele de mai sus vor fi folosite pentru a calcula mai târziu scorul final pentru utilizator.

De aici ne vom concentra acum asupra unor concepte importante legate de sistemele de recomandare.

Similitudine cosinusală

Pentru formula de mai sus trebuie să găsim utilizatorii care au gânduri similare. Acest lucru sună atât de interesant pentru a găsi un utilizator care are simpatii și antipatii similare. Dar întrebarea este cum găsim similitudinea?

Pentru a răspunde la această întrebare, vom folosi Cosine Similarity și vom vedea cât de asemănători sunt utilizatorii. De obicei, aceasta este calculată pe baza evaluărilor pe care ambii utilizatori le-au evaluat în trecut.

În exemplul nostru, am folosit funcția cosine_similarity din sklearn pentru a calcula similitudinea. Dar, înainte de aceasta, trebuie să efectuăm o preprocesare și să curățăm datele.

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

Tabel pivot

Aceasta conține o mulțime de valori NaN, deoarece fiecare utilizator nu a văzut toate filmele și acesta este motivul pentru care acest tip de matrice se numește matrice rară. Metode cum ar fi factorizarea matricei sunt utilizate pentru a face față acestui tip de matrice rarefiată, dar nu ne vom concentra asupra ei în acest blog. Următorul pas și unul dintre pașii importanți este înlocuirea acestor valori NaN.

Există două metode utilizate în mod obișnuit pentru acest lucru :

  1. Utilizați media utilizatorilor pe rând.
  2. Utilizați media filmelor pe coloană.

Am utilizat ambele metode și le puteți obține în codul de mai jos. Dar pentru a explica aș folosi metoda mediei filmului.

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

Înlocuirea valorilor NaN prin media filmului

Acum, următorul pas este să calculăm similaritatea dintre utilizatori.

# 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()

User User User cosine similarity

Să ne verificăm dacă ceea ce am calculat are cu adevărat sens !!

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

filme similare

Din imaginea de mai sus putem vedea că similaritatea pe care am generat-o este adevărată, deoarece ambii utilizatori dați (370,86309) au aproape aceleași evaluări și aprecieri.

Așa că am terminat de calculat similitudinile dintre utilizatori, dar nu sunt încă mulțumit. Voi discuta motivul în pasul următor.

Neighborhood for User (K)

Din cele de mai sus putem vedea că am calculat similitudinile pentru toți utilizatorii. Dar, de când sunt student la Big Data, complexitatea problemei mă conduce întotdeauna. Prin aceasta mă refer la faptul că sistemul de recomandare lucrează cu date uriașe și, prin urmare, devine foarte important să menținem și să capturăm doar elementele importante și necesare din date.

Pentru a explica acest lucru folosind exemplul nostru de sistem de recomandare a filmelor, matricea pe care am obținut-o mai sus este (862*862), deoarece există 862 de utilizatori unici în date. Acest număr este încă mic în comparație cu datele pe care ar trebui să lucreze sistemul original. Să ne gândim la Amazon. Acesta ar avea mai mult de milioane de utilizatori în baza sa de date și, prin urmare, în timpul calculării scorului pentru orice articol, nu ar fi o soluție sau o metodă bună să ne uităm tot timpul la toți ceilalți utilizatori. Prin urmare, pentru a depăși această problemă, generăm o noțiune de vecinătate. Aceasta include doar setul de (K) utilizatori similari pentru un anumit utilizator.

Acum să luăm măsuri suplimentare pentru a implementa ideea. În exemplul nostru am luat valoarea lui k ca fiind 30. Așadar, vom avea 30 de vecini apropiați pentru toți utilizatorii.

Am folosit funcția mea personalizată find_n_neighbours care ia matricea de similaritate și valoarea lui n ca intrare și returnează cei mai apropiați n vecini pentru toți utilizatorii. Puteți găsi codul în caietul de notițe dat la sfârșitul blogului.

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

primarii 30 de vecini pentru utilizatori

Acum, dacă vă gândiți, atunci am redus serios numărul de calcule inutile. Acum, suntem gata să calculăm acum scorul pentru un element.

Generarea scorului final S(u,i)

Wow! am terminat cu procesul. Știu că am trecut prin niște chestii tehnice reale, dar timpul pe care l-am petrecut merită, deoarece am ajuns la ultimul pas.

Aici vom încerca să prezicem scorul pentru filmul pe care utilizatorul dat nu l-a văzut.

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

Scoringul prezis

Atunci sistemul nostru a prezis că scorul va fi 4,25, ceea ce este foarte bine. Cred că utilizatorului (370) i-ar putea plăcea filmul cu id (7371).

Acum să dăm o notă finală sistemului nostru. Cred că cei mai mulți dintre noi ar fi folosit Netflix sau Hotstar. Așa că atunci când deschidem aplicația ne arată elementul pe care îl faceți like.

Întotdeauna sunt fascinat de recomandare, deoarece se dovedește că sunt filmele care îmi plac. Totul se întâmplă prin sistemul de recomandare în sine. Acum vom face același lucru și vom încerca să prezicem primele 5 filme care ar putea să-i placă utilizatorului dat.

Logica nu este atât de grea. Am generat deja scorul pentru un element. În mod similar, putem genera scorul pentru alte articole cu același utilizator.

Dar, dacă luăm din nou în considerare Big Data, are sens să generăm scorul pentru toate celelalte articole?

Cred că NU!!!

Să luăm în considerare utilizatorul (U) și utilizatorul (K). Acum să presupunem că K nu se află în vecinătatea lui U ,este posibil ca utilizatorului U să îi placă un film pe care K l-a văzut și l-a evaluat. În mare parte nu.

Cred că ați prins șmecheria. Da, ne interesează doar să calculăm scorurile pentru elementele pe care utilizatorii vecini le-au văzut.

Am reușit cu adevărat. Am redus calculul de la 2500 la N ( unde N este setul de filme care le-a plăcut vecinilor mei ) și care este foarte mai mic decât 2500.

Acum, în sfârșit, să recomandăm filmele.

User_item_score1 este funcția mea personalizată care folosește discuția noastră de mai sus pentru a calcula predicțiile

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)

În sfârșit!!!! Am reușit. Avem propriul nostru sistem de recomandare.

Reprezentarea codului de mai jos s-ar putea să nu fie foarte ușor de citit, așa că vă rog să mergeți la depozitul meu GitHub pentru a accesa codul.

Datele necesare pot fi obținute de aici.

Sper că v-a plăcut blogul. Pentru orice întrebări îmi puteți trimite un e-mail. Rămâneți la curent cu mai multe bloguri, deoarece acesta este unul dintre domeniile mele de interes și cu siguranță aș posta lucruri noi.

Mulțumesc…!!!

Lasă un răspuns

Adresa ta de email nu va fi publicată.