Aanbeveligingssystemen : User-based Collaborative Filtering using N Nearest Neighbors

Ashay Pathak
Ashay Pathak

Follow

25 feb, 2019 – 9 min read

Ashay Pathak, Chatana Mandava, Ritesh Patel

Collaborative Filtering is een techniek die veel wordt gebruikt in aanbevelingssystemen en is een snel voortschrijdend onderzoeksgebied. De twee meest gebruikte methoden zijn geheugen-gebaseerd en model-gebaseerd.

In deze post zullen we ons alleen richten op (User-Based Collaborative Filtering) UB-CF dat een geheugen-gebaseerde methode is. Het belangrijkste idee achter UB-CF is dat mensen met vergelijkbare kenmerken een vergelijkbare smaak delen. Bijvoorbeeld, als je een film wil aanbevelen aan onze vriend Bob, stel dat Bob en ik samen veel films hebben gezien en dat we ze bijna identiek beoordelen. Het is logisch om te denken dat we ook in de toekomst soortgelijke films leuk zullen vinden en dat we deze gelijkenis gebruiken om films aan te bevelen.

Laten we proberen om UB-CF te implementeren en een lijst van films te genereren die onze vriend Bob a.k.a actieve gebruiker zou kunnen interesseren om te bekijken. De motivatie achter het schrijven van deze post is om diep in het algoritme te duiken en te begrijpen hoe UB-CF eigenlijk werkt. Het grootste deel van de inhoud van deze post is geïnspireerd door een cursus op Coursera.

User-User Collaborative Filtering

De methode identificeert gebruikers die vergelijkbaar zijn met de opgevraagde gebruiker en schat de gewenste beoordeling in als het gewogen gemiddelde van de beoordelingen van deze vergelijkbare gebruikers.

Collaborative Filtering : source here

We zouden de aanbevelingen doen op MovieLens Dataset. De gebruikte programmeertaal is python en voor de gegevensanalyse wordt voornamelijk gebruik gemaakt van de pandas-bibliotheek. De gebruikte IDE is jupyter notebook.

Voordat we beginnen wil ik eerst de lijst van gebruikte bibliotheken geven :

  1. Pandas
  2. Numpy
  3. sklearn

Dus laten we verder gaan en de concepten achter aanbevelingen begrijpen. Ik heb bijgevoegd enkele code snippets en outputs in de blog voor een beter begrip. Het hele ipynb-bestand is aan het eind van de blog bijgevoegd.

Score-functie

Het is eenvoudig om een functie te bedenken voor niet-gepersonaliseerde collaboratieve filtering (dat wil zeggen dat we geen rekening houden met de likes, dislikes en rating van actieve gebruikers uit het verleden) die een score teruggeeft met gebruiker u en item i als invoerparameters. De functie geeft een score die aangeeft hoe sterk gebruiker u item i leuk vindt/voorkeurt.

Dit wordt dus meestal gedaan met behulp van de ratings van andere mensen die vergelijkbaar zijn met de gebruiker. Dit alles zou later in detail worden besproken. Voor nu is de formule die ik heb gebruikt,

score functie

Waarbij ‘s’ de voorspelde score is, ‘u’ de gebruiker is, ‘i’ het item is, ‘r’ de waardering is die de gebruiker heeft gegeven en ‘w’ het gewicht is.

In dit geval is onze score gelijk aan de som van de waarderingen die elke gebruiker aan dat item heeft gegeven, verminderd met de gemiddelde waardering van die gebruiker, vermenigvuldigd met een gewicht dat aangeeft hoeveel deze gebruiker lijkt op of geacht wordt bij te dragen aan de voorspellingen van andere gebruikers. Dit is het gewicht tussen gebruiker u en v. De score varieert van 0 tot 1, waarbij 0 laag is en 1 hoog. Alles ziet er perfect uit, maar waarom hebben we dan de gemiddelde waardering van elke gebruiker afgetrokken en waarom hebben we een gewogen gemiddelde gebruikt in plaats van een eenvoudig gemiddelde?

Het probleem ligt bij de soorten gebruikers die we behandelen. Het begint met het feit dat mensen vaak op zeer verschillende schalen beoordelen. Ik kan een positieve en optimistische gebruiker zijn en de film die ik leuk vond een 4 van de 5 geven, maar een andere gebruiker die minder optimistisch is of hoge eisen stelt, kan zijn favoriete film een 2 van de 5 geven. Hier is zijn 2 mijn 4. De tweaks om het beter te maken is, we kunnen de efficiëntie van dit algoritme verhogen als we de waardering van de gebruiker normaliseren. Een manier om dat te doen is om te zeggen dat we s(u,i) gaan berekenen, d.w.z. de score als de gemiddelde waardering die de gebruiker aan elk item geeft plus een afwijking en de afwijking gaat zijn hoeveel dit item beter of slechter is dan het gemiddelde.

Ik heb de cosinusgelijkenis gebruikt om het gewicht te berekenen dat in de bovenstaande formule wordt gegeven. Ik heb ook het begrip buurt gebruikt, dat in deze blog zou worden besproken als we verder gaan.

Om de gegevens op de bovenstaande manier te normaliseren, is enige gegevensanalyse vereist in pandas. U kunt de hele code aan het einde. Voor deze blog zal ik me concentreren op de belangrijke concepten.

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

Nu zijn we dus klaar met het berekenen van de genormaliseerde rating voor een gebruiker. De bovenstaande gegevens worden later gebruikt om de eindscore voor de gebruiker te berekenen.

Van hieruit gaan we ons nu richten op enkele belangrijke concepten met betrekking tot aanbevelingssystemen.

Cosineovereenkomst

Voor de bovenstaande formule moeten we de gebruikers vinden die vergelijkbare gedachten hebben. Dit klinkt zo interessant om een gebruiker te vinden die gelijksoortige sympathieën en antipathieën heeft. Maar de vraag is hoe vinden we de gelijkenis?

Om dit te beantwoorden, zullen we Cosine Gelijkenis gebruiken en zien hoe gelijk de gebruikers zijn. Deze wordt gewoonlijk berekend over de beoordelingen die beide gebruikers in het verleden hebben gegeven.

In ons voorbeeld heb ik de cosine_similarity-functie van sklearn gebruikt om de gelijkenis te berekenen. Maar daarvoor moeten we eerst wat voorbewerken en de gegevens opschonen.

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

pivot table

Dit bevat een aantal veel NaN-waarden omdat niet elke gebruiker alle films heeft gezien en daarom wordt dit type matrix sparse matrix genoemd. Methoden zoals matrix factorisatie worden gebruikt om met deze karigheid om te gaan, maar daar zullen we ons in deze blog niet op richten. De volgende stap en een van de belangrijkste stappen is het vervangen van deze NaN waarden.

Er zijn twee methoden die hier vaak voor worden gebruikt :

  1. Gebruik het gebruikersgemiddelde over de rij.
  2. Gebruik het filmgemiddelde over de kolom.

Ik heb beide methoden gebruikt en je kunt het in de onderstaande code vinden. Maar voor de uitleg zou ik de methode van het filmgemiddelde gebruiken.

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

Vervangen van NaN-waarden door filmgemiddelde

Nu is de volgende stap het berekenen van de gelijkenis tussen de gebruikers.

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

Gelijkenis gebruiker cosinus

Laten we eens kijken of wat we berekend hebben ook echt zin heeft !

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

films lijken op elkaar

Van bovenstaande afbeelding kunnen we zien dat de overeenkomst die we hebben gegenereerd waar is aangezien beide gebruikers (370,86309) bijna dezelfde beoordelingen en likings hebben.

Dus we zijn klaar met het berekenen van de overeenkomsten tussen de gebruikers, maar ik ben nog niet tevreden. Ik zou de reden hiervoor in de volgende stap bespreken.

Neighborhood for User (K)

Zo uit het bovenstaande kunnen we zien dat we de overeenkomsten voor alle gebruikers hebben berekend. Maar sinds ik een Big Data student ben, drijft de complexiteit van het probleem me altijd. Hiermee bedoel ik dat het aanbevelingssysteem werkt met de enorme gegevens en dus wordt het erg belangrijk om alleen de belangrijke en noodzakelijke hoogtepunten uit de gegevens te behouden en vast te leggen.

Om dit uit te leggen met behulp van ons voorbeeld van filmaanbevelingssysteem, de matrix die we hierboven hebben verkregen is (862*862), omdat er 862 unieke gebruikers in de gegevens zijn. Dit aantal is nog steeds klein in vergelijking met de gegevens waar het originele systeem mee zou werken. Laten we eens denken aan Amazon. Het zou meer dan miljoenen gebruikers in zijn database hebben en dus zou het bij het berekenen van de score voor een item geen goede oplossing of methode zijn om de hele tijd naar alle andere gebruikers te kijken. Om dit te ondervangen genereren we een notie van buurt. Dit omvat alleen de set van (K) vergelijkbare gebruikers voor een bepaalde gebruiker.

Nu laten we verdere stappen nemen om het idee uit te voeren. In ons voorbeeld heb ik de waarde van k als 30 genomen. Dus we zouden 30 naaste buren hebben voor alle gebruikers.

Ik heb mijn aangepaste functie find_n_neighbours gebruikt, die de gelijkenismatrix en de waarde van n als invoer neemt en de dichtstbijzijnde n-buren voor alle gebruikers retourneert. U kunt de code vinden in de notebook aan het einde van de 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 buren voor gebruikers

Dus als u nu denkt dan hebben we het aantal onnodige berekeningen serieus verminderd. Nu zijn we klaar om de score voor een item te berekenen.

Het genereren van de eindscore S(u,i)

Wow! We zijn klaar met het proces. Ik weet dat we door een aantal echte technische dingen zijn gegaan, maar de tijd die we hebben besteed is de moeite waard omdat we de laatste stap hebben bereikt.

Hier zullen we proberen de score te voorspellen voor de film die de gegeven gebruiker niet heeft gezien.

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

voorspelde score

Dus ons systeem voorspelde dat de score 4,25 zou zijn, wat erg goed is. Ik denk dat gebruiker (370) de film leuk zou kunnen vinden met id (7371).

Nu nog een finishing touch geven aan ons systeem. Ik denk dat de meesten van ons zou hebben gebruikt Netflix of Hotstar. Dus wanneer we de app openen het toont het item dat u maakt like.

Ik altijd gefascineerd door de aanbeveling als ze blijken te zijn de films die ik leuk vind. Dit gebeurt allemaal door het aanbevelingssysteem zelf. We gaan nu hetzelfde doen en proberen de top 5 films te voorspellen die de gegeven gebruiker leuk zou kunnen vinden.

De logica is niet zo moeilijk. We hebben de score voor één item al gegenereerd. Op dezelfde manier kunnen we de score voor de andere items met dezelfde gebruiker genereren.

Maar, nu opnieuw rekening houdend met Big Data, heeft het zin om de score voor alle andere items te genereren?

Ik denk NOOOOOOOOOOOOOOOOOO!!!

Laten we eens kijken naar gebruiker (U) en gebruiker (K). Stel nu dat K niet in de buurt van U is, is het dan mogelijk voor gebruiker U om een film leuk te vinden die K heeft gezien en beoordeeld. Meestal niet.

Ik denk dat je de truc doorhebt. Ja, we zijn gewoon geïnteresseerd in het berekenen van de scores voor de items die hun buurman gebruikers hebben gezien.

We zijn echt succesvol. We hebben de berekening teruggebracht van 2500 naar N (waarbij N de reeks films is die mijn buurt leuk vond) en dat is heel wat minder dan 2500.

Dus laten we eindelijk de films aanbevelen.

User_item_score1 is mijn aangepaste functie die gebruik maakt van onze bovenstaande discussie om voorspellingen te berekenen

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)

Eindelijk!!!! Het is ons gelukt. We hebben ons eigen aanbevelingssysteem.

De weergave van de code hieronder is misschien niet erg gemakkelijk te lezen, dus ga naar mijn GitHub-repository om toegang te krijgen tot de code.

De benodigde Datasets kunnen hier worden verkregen.

Ik hoop dat je de blog leuk vond. Voor eventuele vragen kunt u mij mailen. Blijf op de hoogte voor meer blogs, want dit is een van mijn interessegebieden en ik zou zeker posten wat nieuwe stuff.

Dank je wel..!!

Geef een antwoord

Het e-mailadres wordt niet gepubliceerd.