Terug naar artikelen

Collaborative Filtering

Bouw een productiewaardig aanbevelingssysteem met gebruiker-item matrices en impliciete feedback.

Aanbevelingssysteem met collaborative filtering

Aanbevelingssystemen

Voorspellen wat een klant als volgende wil consumeren heeft aanzienlijke economische waarde. Je kunt echter maar een beperkt aantal items tegelijk voorstellen, dus het is cruciaal dat je aanbevelingen zo relevant mogelijk zijn.

Aanbevelingssystemen zijn bijna overal te vinden; op videostreamingplatforms zoals Netflix, Disney+ en YouTube, audiostreamingdiensten zoals Spotify, en e-commerceplatforms zoals Amazon, AliExpress en Bol.com. In de meeste gevallen zijn de systemen zeer geavanceerd en bestaan ze uit veel verschillende componenten.

In dit artikel demonstreren we een eenvoudig aanbevelingssysteem gebaseerd op de speeltijd van games gespeeld door gebruikers op Steam.

Spring gerust vooruit naar de demo van het aanbevelingssysteem als je wilt.

Collaborative filtering vs content-based filtering

Aanbevelingssystemen kunnen over het algemeen in twee hoofdbenaderingen worden verdeeld:

  • Collaborative filtering: je zult waarschijnlijk items leuk vinden die vergelijkbare gebruikers leuk vonden.
  • Content-based filtering: je zult waarschijnlijk items leuk vinden die vergelijkbare eigenschappen delen met wat je al hebt geconsumeerd.
De stappen van dit project

Collaborative filtering richt zich op de relaties tussen gebruikers en items. Het vereist geen kennis over de items zelf; alleen informatie over gebruikersgedrag, zoals beoordelingen, aankopen of betrokkenheid. Als twee gebruikers in het verleden vergelijkbare voorkeuren hebben getoond, gaat het systeem ervan uit dat hun toekomstige interesses ook overeen zullen komen.

Content-based filtering daarentegen vertrouwt op de kenmerken of eigenschappen van de items. Bijvoorbeeld, in een filmaanbevelingssysteem kan het metadata gebruiken zoals genre, regisseur, cast of beschrijving. Het systeem beveelt dan andere items aan met vergelijkbare eigenschappen als wat de gebruiker al leuk vond.

Terwijl collaborative filtering onverwachte relaties tussen gebruikers en items kan ontdekken, worstelt het met nieuwe gebruikers of nieuwe items (het cold start probleem). Content-based filtering kan daarentegen direct aanbevelingen doen voor nieuwe gebruikers zolang hun voorkeuren bekend zijn; maar het kan falen om diverse of verrassende opties buiten de bestaande interesses van de gebruiker voor te stellen.

Projectplan

De stappen van dit project

Dit project is in verschillende stappen uitgevoerd:

  • Data opschonen (niet getoond in de visual)
  • Datavoorbereiding: logaritmische transformatie en IDF-schaling toepassen
  • Output 1: UMAP datavisualisatie
  • Output 2: KNN toegepast op SVD-features

Deze stappen worden in de volgende secties uiteengezet.

Data

In dit artikel verkennen we de kracht van collaborative filtering met data van Steam. Na het opschonen van de dataset hebben we informatie over 3.307 gebruikers en 4.851 games verkregen.

De dataset bevat de speeltijd (in uren) per gebruiker per game, wat het interactieniveau van elke gebruiker met een game vertegenwoordigt. In dit artikel verwijs ik naar de consument als klant, gebruiker of speler, en naar het item als game of product.

Op basis van deze data kunnen we voorspellen hoeveel tijd een klant waarschijnlijk aan een nieuwe game zal besteden, gegeven wat andere, vergelijkbare klanten hebben gespeeld.

Het aantal klanten in deze dataset is lager dan ideaal; idealiter zouden we meerdere keren meer gebruikers dan items hebben. Door deze onbalans kunnen sommige aanbevelingen enigszins ongebruikelijk lijken, wanneer een paar gebruikers minder typisch gedrag vertonen. Het verzamelen en voorbereiden van deze data was echter al behoorlijk tijdrovend, dus het zal goed genoeg dienen voor demonstratiedoeleinden.

user_idgameplaytime
5072280Undertale10.0
8182206Half-Life 2: Deathmatch2.7
4522280The Wolf Among Us26.8
36895Tales of Berseria0.0
24295The Witcher: Enhanced Edition9.2
9292542Batman: Arkham Asylum GOTY Edition33.6
26295Call of Duty: Modern Warfare Remastered (2017)4.9
8102206Sid Meier's Civilization VI6.2
31895Arma: Cold War Assault0.0
492486BioShock Remastered18.0

Datavoorbewerking

Voordat we ons aanbevelingsmodel bouwen, moeten we de data opschonen en voorbereiden zodat deze geschikter is voor het genereren van zinvolle aanbevelingen.

Het aantal uren gespeeld per game per speler. Zoals je kunt zien, spelen sommige spelers een game zeer uitgebreid, en veel worden nauwelijks gespeeld. Rechts: volledig bereik, Links: ingezoomd tot minder dan 40 uur

Zelden gespeelde games verwijderen

Onze dataset bevat veel meer games dan gebruikers, en een groot aantal van deze games wordt zelden gespeeld. Om datakwaliteit te waarborgen, heb ik twee filters toegepast:

  • Games moeten een gemiddelde speeltijd van meer dan 2 uur hebben.
  • Games moeten door minimaal 5 spelers gespeeld zijn.

Daarnaast moet een speler een game minimaal 1 uur gespeeld hebben om meegeteld te worden. Hoewel deze drempel minimaal is, kan zelfs een kleine hoeveelheid speeltijd nuttige informatie over spelersinteresse bieden.

Hetzelfde als hiervoor: het aantal uren gespeeld per game per speler. Maar nu na het verwijderen van zelden gespeelde games. Met de toevoeging van de natuurlijke log-distributie rechts.

Speeltijd transformeren

Ruwe speeltijddata kan behoorlijk grillig zijn. Bijvoorbeeld, als een game ongeveer 10 uur duurt om uit te spelen en een gebruiker besluit het tien keer opnieuw te spelen, betekent dat dan dat ze het tien keer leuker vinden dan iemand die het één keer uitspeelt? Of als de ene gebruiker 20 uur vrije tijd per week heeft en een andere slechts 10 uur per maand, betekent dat dan dat de eerste gebruiker de game leuker vindt dan de tweede?

Deze inconsistenties maken ruwe speeltijd misleidend. Om scheefheid te verminderen en de data beter vergelijkbaar te maken, passen we een natuurlijke logaritmische transformatie toe. Met andere woorden, ongeveer 2,7 keer meer speeltijd consumeren verhoogt de getransformeerde waarde met +1. Bijvoorbeeld, een speler die 10 uur aan een game besteedt krijgt een waarde van 2,3, terwijl een ander die 100 uur speelt 4,6 krijgt. Deze transformatie voorkomt dat zware spelers de data domineren en geeft matige spelers een evenwichtigere vertegenwoordiging in het algoritme.

Schaling over games en spelers

Je zou ook kunnen overwegen om speeltijd per game of per speler te schalen. Sommige games vereisen van nature meer tijd om uit te spelen; Portal kost bijvoorbeeld ongeveer 20 uur, terwijl een MMORPG gemakkelijk meer dan 100 uur kan overschrijden zonder een eindpunt te bereiken. Evenzo besteden sommige spelers over het algemeen veel meer tijd aan gamen dan anderen. Hoewel de logaritmische transformatie dit effect al verzacht, kunnen we per-gebruiker schaling toepassen om spelers verder te normaliseren op dezelfde schaal.

Ik heb geëxperimenteerd met verschillende schalingstechnieken op zowel spelers als games, waaronder normalisatie (max-abs schaling), standaardisatie (zonder centreren rond het gemiddelde), kwantielschaling en TF-IDF zonder de TF-component (dus alleen inverse document frequency (IDF)).

Van deze methoden leverde alleen de IDF-benadering enigszins veelbelovende resultaten op. Het gedraagt zich echter heel anders dan traditionele schalingsmethoden; het boost games die minder vaak gespeeld worden, waardoor extra gewicht wordt gegeven aan niche-items waar minder gebruikers mee interacteren.

Voor deze versie is geen aanvullende schaling toegepast. Dit betekent dat langere en kortere games, evenals spelers die meer of minder spelen, gelijk worden behandeld in de dataset.

Visuele aanbevelingen

Een manier om te verkennen welke producten het beste bij je passen is door visueel te inspecteren welke items door dezelfde klanten worden gebruikt. Dit wordt echter uitdagend wanneer elke klant met honderden of zelfs duizenden producten interacteert; de data bestaat dan in een extreem hoog-dimensionale ruimte. Om het interpreteerbaar te maken, moeten we het reduceren tot minder dimensies, bij voorkeur twee, zodat het geplot en visueel verkend kan worden.

Technieken zoals PCA (Principal Component Analysis) of SVD (Singular Value Decomposition) kunnen worden gebruikt voor dimensionaliteitsreductie, maar ze zijn beperkt tot lineaire combinaties van de originele features. Als je duidelijkere scheiding tussen groepen van vergelijkbare items wilt, is UMAP (Uniform Manifold Approximation and Projection) een zeer goed alternatief. Hoewel UMAP minder intuïtief is in hoe het punten rangschikt vergeleken met PCA of SVD, creëert het over het algemeen meer onderscheidende clusters, wat helpt om patronen in gebruikersgedrag te onthullen.

Hieronder zie je een projectie van de productruimte, waarbij IDF is toegepast over spelers voorafgaand aan UMAP-dimensionaliteitsreductie. Deze combinatie produceerde de meest onderscheidende en visueel zinvolle groeperingen.

Loading chart…

Controleren op vergelijkbare consumenten

Een andere manier om games aan te bevelen is door direct te onderzoeken wat vergelijkbare gebruikers hebben gespeeld. Een eenvoudige benadering is om te kijken wat een bepaald aantal andere mensen; die dezelfde games leuk vonden; ook hebben gespeeld. Deze techniek staat bekend als de nearest neighbours methode.

Onze dataset bevat echter slechts ongeveer 3.307 gebruikers en 4.851 games. Hoewel dat substantieel klinkt, betekent het eigenlijk dat veel mogelijke gebruiker-game combinaties ontbreken. Hierdoor kan deze benadering nogal hit or miss zijn, omdat het systeem vaak niet genoeg overlap tussen gebruikers heeft om betrouwbare aanbevelingen te doen.

Controleren op vergelijkbare archetypes

Onze data is zeer sparse, wat betekent dat het veel nulwaarden bevat en slechts een paar geregistreerde interacties per gebruiker. Deze sparsity veroorzaakte problemen met de eerdere nearest neighbours benadering, waar het moeilijk was om genoeg overlappende gebruikers te vinden.

Veel games zijn echter van nature vergelijkbaar, en vergelijkbare spelers hebben misschien net iets andere gespeeld. Bijvoorbeeld, misschien heb jij Satisfactory gespeeld terwijl je vriend Factorio speelde. Hoewel deze games niet identiek zijn, lijken ze duidelijk meer op elkaar dan, zeg, Counter-Strike 2.

Dus in plaats van gebruikers direct te vergelijken, kunnen we zoeken naar spelersarchetypes; groepen spelers die vergelijkbare onderliggende voorkeuren delen. We kunnen deze archetypes creëren door dimensionaliteitsreductie, waarbij de consumentenruimte wordt gecomprimeerd tot een kleinere, latente "archetype"-ruimte. Zodra deze transformatie is toegepast, wordt het veel gemakkelijker om games te vergelijken en zinvolle relaties ertussen te identificeren.

Probeer het hieronder uit:

Loading recommender…

Er zijn verschillende ontwerpkeuzes bij betrokken; bijvoorbeeld welke schalingsmethode en welke dimensionaliteitsreductietechniek te gebruiken. Door te experimenteren leverde de combinatie van TF-IDF (zonder de TF-component) en Singular Value Decomposition (SVD) met 27 dimensies de meest intuïtieve resultaten op.

Het is ook leuk om te experimenteren met combinaties van games; wanneer je meerdere games selecteert, berekent het systeem de gemiddelde vector van hun embeddings, waardoor effectief hun archetypische features worden gemengd om gerelateerde titels voor te stellen.

Discussie

De demo lijkt over het geheel genomen goed te werken. De visualisatie is aantrekkelijk en de aanbevelingen zijn redelijk goed.

Dat gezegd hebbende, is er nog ruimte voor verbetering:

  • Er is nog geen content-based informatie opgenomen.
  • Het aantal gebruikers in de dataset zou idealiter veel groter moeten zijn.
  • Een niet-lineaire dimensionaliteitsreductietechniek, zoals een autoencoder, zou betere resultaten kunnen opleveren.
  • Het schalen van games op verwachte betrokkenheid zou ook gunstig kunnen zijn indien zorgvuldig geïmplementeerd.

Van deze punten is de steekproefgrootte waarschijnlijk het meest impactvol. Zoals bij de meeste machine learning modellen, zijn de kwaliteit en kwantiteit van data belangrijker dan de complexiteit van het algoritme. Hoe geavanceerd je model ook is, het kan geen "magie" verrichten zonder voldoende zinvolle data. Sommige aanbevelingen voelen nog een beetje willekeurig, en dat komt waarschijnlijk door de kleine dataset.

Op een gegeven moment zal ik deze dataset waarschijnlijk hergebruiken in mijn machine learning cursus, die ik momenteel aan het ontwikkelen ben. Het is een leuke en praktische dataset; een uitstekend voorbeeld voor het illustreren van aanbevelingstechnieken.

Al met al werkt dit prototype goed genoeg voor de reikwijdte van dit artikel. Ik hoop dat je het leuk vond en er misschien zelfs iets nuttigs aan hebt gehad.