Predicția like-urilor: în algoritmii unui motor de recomandare simplu
Publicat: 2022-03-11Un motor de recomandare (uneori denumit sistem de recomandare) este un instrument care le permite dezvoltatorilor de algoritmi să prezică ce îi poate plăcea sau nu unui utilizator dintr-o listă de elemente date. Motoarele de recomandare sunt o alternativă destul de interesantă la câmpurile de căutare, deoarece motoarele de recomandare îi ajută pe utilizatori să descopere produse sau conținut pe care nu le întâlnesc altfel. Acest lucru face ca motoarele de recomandare să fie o mare parte a site-urilor web și a serviciilor precum Facebook, YouTube, Amazon și altele.
Motoarele de recomandare funcționează ideal într-unul din două moduri. Se poate baza pe proprietățile articolelor care îi plac unui utilizator, care sunt analizate pentru a determina ce altceva i-ar putea plăcea utilizatorului; sau, se poate baza pe aprecierile și antipatiile altor utilizatori, pe care motorul de recomandare le folosește apoi pentru a calcula un indice de similitudine între utilizatori și pentru a le recomanda articole în consecință. De asemenea, este posibil să combinați ambele metode pentru a construi un motor de recomandare mult mai robust. Cu toate acestea, la fel ca toate celelalte probleme legate de informații, este esențial să alegeți un algoritm care este potrivit pentru problema abordată.
În acest tutorial, vă vom ghida prin procesul de construire a unui motor de recomandare care este colaborativ și bazat pe memorie. Acest motor de recomandare va recomanda filme utilizatorilor în funcție de ceea ce le place și nu le place și va funcționa ca al doilea exemplu menționat anterior. Pentru acest proiect, vom folosi operații de bază cu set, puțină matematică și Node.js/CoffeeScript. Tot codul sursă relevant pentru acest tutorial poate fi găsit aici.
Mulțimi și ecuații
Înainte de a implementa un motor de recomandare colaborativ bazat pe memorie, trebuie să înțelegem mai întâi ideea de bază din spatele unui astfel de sistem. Pentru acest motor, fiecare articol și fiecare utilizator nu sunt altceva decât identificatori. Prin urmare, nu vom lua în considerare niciun alt atribut al unui film (de exemplu, distribuția, regizorul, genul etc.) atunci când generăm recomandări. Asemănarea dintre doi utilizatori este reprezentată folosind un număr zecimal între -1,0 și 1,0. Vom numi acest număr indicele de asemănare. În cele din urmă, posibilitatea ca un utilizator să-i placă un film va fi reprezentată folosind un alt număr zecimal între -1,0 și 1,0. Acum că am modelat lumea din jurul acestui sistem folosind termeni simpli, putem dezlănțui o mână de ecuații matematice elegante pentru a defini relația dintre acești identificatori și numere.
În algoritmul nostru de recomandare, vom menține un număr de seturi. Fiecare utilizator va avea două seturi: un set de filme care îi plac utilizatorului și un set de filme pe care utilizatorul nu le place. Fiecare film va avea, de asemenea, două seturi asociate: un set de utilizatori cărora le-a plăcut filmul și un set de utilizatori cărora nu le-a plăcut filmul. În etapele în care sunt generate recomandări, vor fi produse un număr de seturi - în mare parte uniuni sau intersecții ale celorlalte seturi. Vom avea, de asemenea, liste ordonate de sugestii și utilizatori similari pentru fiecare utilizator.
Pentru a calcula indicele de similaritate, vom folosi o variație a formulei indicelui Jaccard. Cunoscută inițial ca „coeficient de comună” (inventat de Paul Jaccard), formula compară două seturi și produce o statistică zecimală simplă între 0 și 1,0:
Formula presupune împărțirea numărului de elemente comune din fiecare set cu numărul tuturor elementelor (numărate o singură dată) din ambele seturi. Indicele Jaccard a două seturi identice va fi întotdeauna 1, în timp ce indicele Jaccard a două seturi fără elemente comune va da întotdeauna 0. Acum că știm cum să comparăm două seturi, să ne gândim la o strategie pe care o putem folosi pentru a compara două. utilizatorii. După cum s-a discutat mai devreme, utilizatorii, din punctul de vedere al sistemului, sunt trei lucruri: un identificator, un set de filme apreciate și un set de filme neplăcute. Dacă ar fi să definim indicele de similitudine al utilizatorilor noștri bazat doar pe setul de filme preferate, am putea folosi direct formula indexului Jaccard:
Aici, U1 și U2 sunt cei doi utilizatori pe care îi comparăm, iar L1 și L2 sunt seturile de filme pe care U1 și, respectiv, U2 le-au plăcut. Acum, dacă vă gândiți bine, doi utilizatori care le plac aceleași filme sunt similare, atunci doi utilizatori care nu le plac aceleași filme ar trebui să fie și ei similari. Aici modificăm puțin ecuația:
În loc să luăm în considerare doar aprecierile obișnuite în numărătorul formulei, acum adăugăm și numărul de aprecieri obișnuite. În numitor, luăm numărul tuturor articolelor pe care fie le-a plăcut sau nu le-a plăcut fiecaruia dintre utilizatori. Acum că am luat în considerare atât aprecierile, cât și antipatiile într-un fel independent, ar trebui să ne gândim și la cazul în care doi utilizatori sunt polar opuși în preferințele lor. Indicele de similitudine a doi utilizatori în care unuia îi place un film și celuilalt nu îi place nu ar trebui să fie 0:
Aceasta este o formulă lungă! Dar e simplu, promit. Este similar cu formula noastră anterioară, cu o mică diferență în numărător. Acum scădem numărul de aprecieri și antipatii conflictuale ale celor doi utilizatori din numărul de aprecieri și antipatii comune. Acest lucru face ca formula indicelui de similaritate să aibă un interval de valori între -1,0 și 1,0. Doi utilizatori care au gusturi identice vor avea un indice de similaritate de 1,0, în timp ce doi utilizatori care au gusturi total conflictuale în filme vor avea un indice de similaritate de -1,0.
Acum că știm cum să comparăm doi utilizatori în funcție de gusturile lor pentru filme, trebuie să mai explorăm o formulă înainte de a începe să implementăm algoritmul motorului nostru de recomandare homebrew:
Să descompun puțin această ecuație. Ceea ce înțelegem prin P(U,M)
este posibilitatea ca un utilizator U
să-i placă filmul M
. ZL
și ZD
sunt suma indicilor de similaritate ai utilizatorului U
cu toți utilizatorii cărora le-a plăcut sau nu le-a plăcut filmul M
. |ML|+|MD|
reprezintă numărul total de utilizatori cărora le-a plăcut sau nu le-a plăcut filmul M
. Rezultatul P(U,M)
produce un număr între -1,0 și 1,0.
Cam atât. În secțiunea următoare, putem folosi aceste formule pentru a începe implementarea motorului nostru de recomandare colaborativ bazat pe memorie.
Construirea motorului de recomandare
Vom construi acest motor de recomandare ca o aplicație Node.js foarte simplă. De asemenea, va fi foarte puțină muncă pe front-end, mai ales unele pagini și formulare HTML (vom folosi Bootstrap pentru a face paginile să arate bine). Pe partea de server, vom folosi CoffeeScript. Aplicația va avea câteva rute GET și POST. Chiar dacă în aplicație vom avea noțiunea de utilizatori, nu vom avea niciun mecanism elaborat de înregistrare/login. Pentru persistență, vom folosi pachetul Bourne disponibil prin NPM, care permite unei aplicații să stocheze date în fișiere JSON simple și să efectueze interogări de bază ale bazei de date asupra acestora. Vom folosi Express.js pentru a ușura procesul de gestionare a rutelor și a handlerelor.
În acest moment, dacă sunteți nou în dezvoltarea Node.js, este posibil să doriți să clonați depozitul GitHub, astfel încât să fie mai ușor să urmați acest tutorial. Ca și în cazul oricărui alt proiect Node.js, vom începe prin a crea un fișier package.json și vom instala un set de pachete de dependență necesare pentru acest proiect. Dacă utilizați depozitul clonat, fișierul package.json ar trebui să fie deja acolo, de unde instalarea dependențelor vă va cere să executați „$ npm install”. Aceasta va instala toate pachetele listate în fișierul package.json.
Pachetele Node.js de care avem nevoie pentru acest proiect sunt:
- asincron
- bourne
- cafea-script
- expres
- jad
- sublinia
Vom construi motorul de recomandare împărțind toate metodele relevante în patru clase separate de CoffeeScript, fiecare dintre acestea fiind stocată în „lib/engine”: Engine, Rater, Similars și Suggestions. Clasa Engine va fi responsabilă pentru furnizarea unui API simplu pentru motorul de recomandare și va lega celelalte trei clase împreună. Evaluatorul va fi responsabil pentru urmărirea aprecierilor și neaprecierii (ca două cazuri separate ale clasei Evaluatorului). Asemănările și Sugestiile vor fi responsabile pentru determinarea și urmărirea utilizatorilor similari și, respectiv, articolele recomandate pentru utilizatori.
Urmărirea aprecierilor și antipatiilor
Să începem mai întâi cu clasa noastră de evaluatori. Acesta este unul simplu:
class Rater constructor: (@engine, @kind) -> add: (user, item, done) -> remove: (user, item, done) -> itemsByUser: (user, done) -> usersByItem: (item, done) ->
După cum s-a indicat mai devreme în acest tutorial, vom avea o instanță de Rater pentru aprecieri și alta pentru neapreciere. Pentru a înregistra că unui utilizator îi place un articol, îl vom transmite către „Rater#add()”. În mod similar, pentru a elimina evaluarea, le vom trece la „Rater#remove()”.
Deoarece folosim Bourne ca o soluție de bază de date fără server, vom stoca aceste evaluări într-un fișier numit „./db-#{@kind}.json”, unde felul este fie „aprecie”, fie „nu-mi place”. Vom deschide baza de date în interiorul constructorului instanței Rater:
constructor: (@engine, @kind) -> @db = new Bourne "./db-#{@kind}.json"
Acest lucru va face adăugarea înregistrărilor de evaluare la fel de simplă precum apelarea unei metode de bază de date Bourne în cadrul metodei noastre „Rater#add()”:
@db.insert user: user, item: item, (err) =>
Și este similar să le eliminați („db.delete” în loc de „db.insert”). Cu toate acestea, înainte de a adăuga sau de a elimina ceva, trebuie să ne asigurăm că nu există deja în baza de date. În mod ideal, cu o bază de date reală, am fi putut-o face ca o singură operație. Cu Bourne, trebuie să facem mai întâi o verificare manuală; și, odată ce inserarea sau ștergerea este finalizată, trebuie să ne asigurăm că recalculăm indicii de similaritate pentru acest utilizator și apoi generăm un set de sugestii noi. Metodele „Rater#add()” și „Rater#remove()” vor arăta cam așa:
add: (user, item, done) -> @db.find user: user, item: item, (err, res) => if res.length > 0 return done() @db.insert user: user, item: item, (err) => async.series [ (done) => @engine.similars.update user, done (done) => @engine.suggestions.update user, done ], done remove: (user, item, done) -> @db.delete user: user, item: item, (err) => async.series [ (done) => @engine.similars.update user, done (done) => @engine.suggestions.update user, done ], done
Pentru concizie, vom sări peste părțile în care verificăm erorile. Acesta ar putea fi un lucru rezonabil de făcut într-un articol, dar nu este o scuză pentru ignorarea erorilor din codul real.
Celelalte două metode, „Rater#itemsByUser()” și „Rater#usersByItem()” ale acestei clase vor implica să faceți ceea ce implică numele lor - căutarea articolelor evaluate de un utilizator și, respectiv, utilizatorii care au evaluat un articol. De exemplu, când Rater este instanțiat cu kind = “likes”
, „Rater#itemsByUser()” va găsi toate articolele pe care utilizatorul le-a evaluat.
Găsirea utilizatorilor similari
Trecem la următoarea noastră clasă: Similare. Această clasă ne va ajuta să calculăm și să ținem evidența indicilor de similaritate dintre utilizatori. După cum sa discutat mai devreme, calcularea asemănării dintre doi utilizatori implică analiza seturilor de articole care le plac și nu le plac. Pentru a face acest lucru, ne vom baza pe instanțele Evaluatorului pentru a prelua seturile de articole relevante și apoi vom determina indicele de similaritate pentru anumite perechi de utilizatori folosind formula indicelui de similaritate.
La fel ca clasa noastră anterioară, Rater, vom pune totul într-o bază de date Bourne numită „./db-similars.json”, pe care o vom deschide în constructorul Rater. Clasa va avea o metodă „Similars#byUser()”, care ne va permite să căutăm utilizatori similari unui anumit utilizator printr-o simplă căutare a bazei de date:
@db.findOne user: user, (err, {others}) =>
Cu toate acestea, cea mai importantă metodă a acestei clase este „Similars#update()” care funcționează prin luarea unui utilizator și calculând o listă de alți utilizatori care sunt similari și stocând lista în baza de date, împreună cu indicii de similaritate ai acestora. Începe prin a găsi aprecierile și antipatiile utilizatorului:

async.auto userLikes: (done) => @engine.likes.itemsByUser user, done userDislikes: (done) => @engine.dislikes.itemsByUser user, done , (err, {userLikes, userDislikes}) => items = _.flatten([userLikes, userDislikes])
De asemenea, găsim toți utilizatorii care au evaluat aceste articole:
async.map items, (item, done) => async.map [ @engine.likes @engine.dislikes ], (rater, done) => rater.usersByItem item, done , done , (err, others) =>
Apoi, pentru fiecare dintre acești alți utilizatori, calculăm indicele de similitudine și îl stocăm pe tot în baza de date:
async.map others, (other, done) => async.auto otherLikes: (done) => @engine.likes.itemsByUser other, done otherDislikes: (done) => @engine.dislikes.itemsByUser other, done , (err, {otherLikes, otherDislikes}) => done null, user: other similarity: (_.intersection(userLikes, otherLikes).length+_.intersection(userDislikes, otherDislikes).length-_.intersection(userLikes, otherDislikes).length-_.intersection(userDislikes, otherLikes).length) / _.union(userLikes, otherLikes, userDislikes, otherDislikes).length , (err, others) => @db.insert user: user others: others , done
În fragmentul de mai sus, veți observa că avem o expresie identică în natură cu formula noastră de indice de similaritate, o variantă a formulei de indice Jaccard.
Generarea de Recomandări
Următoarea noastră clasă, Sugestii, este locul în care au loc toate predicțiile. Ca și clasa Similars, ne bazăm pe o altă bază de date Bourne numită „./db-suggestions.json”, deschisă în interiorul constructorului.
Clasa va avea o metodă „Suggestions#forUser()” pentru a căuta sugestii calculate pentru utilizatorul dat:
forUser: (user, done) -> @db.findOne user: user, (err, {suggestions}={suggestion: []}) -> done null, suggestions
Metoda care va calcula aceste rezultate este „Suggestions#update()”. Această metodă, precum „Similars#update()”, va lua un utilizator ca argument. Metoda începe prin a enumera toți utilizatorii similari cu utilizatorul dat și toate articolele pe care utilizatorul dat nu le-a evaluat:
@engine.similars.byUser user, (err, others) => async.auto likes: (done) => @engine.likes.itemsByUser user, done dislikes: (done) => @engine.dislikes.itemsByUser user, done items: (done) => async.map others, (other, done) => async.map [ @engine.likes @engine.dislikes ], (rater, done) => rater.itemsByUser other.user, done , done , done , (err, {likes, dislikes, items}) => items = _.difference _.unique(_.flatten items), likes, dislikes
Odată ce avem listați toți ceilalți utilizatori și articolele neevaluate, putem începe să calculăm un nou set de recomandări eliminând orice set anterior de recomandări, repetând fiecare articol și calculând posibilitatea ca utilizatorul să-l placă pe baza informațiilor disponibile:
@db.delete user: user, (err) => async.map items, (item, done) => async.auto likers: (done) => @engine.likes.usersByItem item, done dislikers: (done) => @engine.dislikes.usersByItem item, done , (err, {likers, dislikers}) => numerator = 0 for other in _.without _.flatten([likers, dislikers]), user other = _.findWhere(others, user: other) if other? numerator += other.similarity done null, item: item weight: numerator / _.union(likers, dislikers).length , (err, suggestions) =>
Odată ce este făcut, îl salvăm înapoi în baza de date:
@db.insert user: user suggestions: suggestions , done
Expunerea API-ului Library
În cadrul clasei Engine, legăm totul într-o structură asemănătoare API-ului pentru un acces ușor din lumea exterioară:
class Engine constructor: -> @likes = new Rater @, 'likes' @dislikes = new Rater @, 'dislikes' @similars = new Similars @ @suggestions = new Suggestions @
Odată ce instanțiem un obiect Engine:
e = new Engine
Putem adăuga sau elimina cu ușurință aprecieri și dislikes:
e.likes.add user, item, (err) -> e.dislikes.add user, item, (err) ->
De asemenea, putem începe să actualizăm indici și sugestii de similaritate utilizatorilor:
e.similars.update user, (err) -> e.suggestions.update user, (err) ->
În cele din urmă, este important să exportați această clasă Engine (și toate celelalte clase) din fișierele respective „.coffee”:
module.exports = Engine
Apoi, exportați Motorul din pachet creând un fișier „index.coffee” cu o singură linie:
module.exports = require './engine'
Crearea interfeței cu utilizatorul
Pentru a putea folosi algoritmul motorului de recomandare în acest tutorial, dorim să oferim o interfață de utilizator simplă pe web. Pentru a face acest lucru, generăm o aplicație Express în fișierul nostru „web.iced” și gestionăm câteva rute:
movies = require './data/movies.json' Engine = require './lib/engine' e = new Eengine app = express() app.set 'views', "#{__dirname}/views" app.set 'view engine', 'jade' app.route('/refresh') .post(({query}, res, next) -> async.series [ (done) => e.similars.update query.user, done (done) => e.suggestions.update query.user, done ], (err) => res.redirect "/?user=#{query.user}" ) app.route('/like') .post(({query}, res, next) -> if query.unset is 'yes' e.likes.remove query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" else e.dislikes.remove query.user, query.movie, (err) => e.likes.add query.user, query.movie, (err) => if err? return next err res.redirect "/?user=#{query.user}" ) app.route('/dislike') .post(({query}, res, next) -> if query.unset is 'yes' e.dislikes.remove query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" else e.likes.remove query.user, query.movie, (err) => e.dislikes.add query.user, query.movie, (err) => res.redirect "/?user=#{query.user}" ) app.route('/') .get(({query}, res, next) -> async.auto likes: (done) => e.likes.itemsByUser query.user, done dislikes: (done) => e.dislikes.itemsByUser query.user, done suggestions: (done) => e.suggestions.forUser query.user, (err, suggestions) => done null, _.map _.sortBy(suggestions, (suggestion) -> -suggestion.weight), (suggestion) => _.findWhere movies, id: suggestion.item , (err, {likes, dislikes, suggestions}) => res.render 'index', movies: movies user: query.user likes: likes dislikes: dislikes suggestions: suggestions[...4] )
În cadrul aplicației, gestionăm patru rute. Ruta de index „/” este locul în care servim HTML-ul front-end prin redarea unui șablon Jade. Generarea șablonului necesită o listă de filme, numele de utilizator al utilizatorului curent, aprecierile și displacele utilizatorului și primele patru sugestii pentru utilizator. Codul sursă al șablonului Jade este lăsat în afara articolului, dar este disponibil în depozitul GitHub.
Rutele „/like” și „/dislike” sunt acolo unde acceptăm solicitările POST pentru a înregistra aprecierile și dislike-urile utilizatorului. Ambele rute adaugă o evaluare eliminând mai întâi orice evaluare conflictuală, dacă este necesar. De exemplu, un utilizator care i-a plăcut ceva care anterior nu i-a plăcut va determina gestionatorul să elimine mai întâi evaluarea „Nu-mi place”. Aceste rute permit, de asemenea, utilizatorului să „dez-aprecieze” sau să „nu aprecieze” un articol, dacă dorește.
În cele din urmă, ruta „/refresh” permite utilizatorului să-și regenereze setul de recomandări la cerere. Deși, această acțiune este efectuată automat ori de câte ori utilizatorul face o evaluare unui articol.
Test-drive
Dacă ați încercat să implementați această aplicație de la zero urmând acest articol, va trebui să efectuați un ultim pas înainte de a o putea testa. Va trebui să creați un fișier „.json” la „data/movies.json” și să îl completați cu câteva date de film, astfel:
[ { "id": "1", "name": "Transformers: Age of Extinction", "thumb": { "url": "//upload.wikimedia.org/wikipedia/en/7/7f/Inception_ver3.jpg" } }, // … ]
Poate doriți să copiați pe cel disponibil în depozitul GitHub, care este pre-populat cu câteva nume de filme și adrese URL în miniatură.
Odată ce tot codul sursă este gata și conectat împreună, pornirea procesului de server necesită invocarea următoarei comenzi:
$ npm start
Presupunând că totul a mers fără probleme, ar trebui să vedeți următorul text care apare pe terminal:
Listening on 5000
Deoarece nu am implementat niciun sistem adevărat de autentificare a utilizatorului, aplicația prototip se bazează doar pe un nume de utilizator ales după accesarea „http://localhost:5000”. Odată ce un nume de utilizator a fost introdus și formularul este trimis, ar trebui să fiți dus la o altă pagină cu două secțiuni: „Filme recomandate” și „Toate filmele”. Deoarece ne lipsește cel mai important element al unui motor de recomandare colaborativ bazat pe memorie (date), nu vom putea recomanda niciun film acestui nou utilizator.
În acest moment, ar trebui să deschideți o altă fereastră de browser la „http://localhost:5000” și să vă conectați ca alt utilizator acolo. Îmi plac și nu-ți plac unele filme ca acest al doilea utilizator. Reveniți la fereastra browserului primului utilizator și evaluați și câteva filme. Asigurați-vă că evaluați cel puțin câteva filme comune pentru ambii utilizatori. Ar trebui să începeți să vedeți recomandări imediat.
Îmbunătățiri
În acest tutorial de algoritm, ceea ce am construit este un motor de recomandare prototip. Există cu siguranță modalități de a îmbunătăți acest motor. Această secțiune va aborda pe scurt unele domenii în care îmbunătățirile sunt esențiale pentru ca aceasta să fie utilizată la scară largă. Cu toate acestea, în cazurile în care sunt necesare scalabilitate, stabilitate și alte asemenea proprietăți, ar trebui să recurgeți întotdeauna la utilizarea unei soluții bune, testate în timp. La fel ca și restul articolului, ideea aici este de a oferi o perspectivă asupra modului în care funcționează un motor de recomandare. În loc să discutăm despre defectele evidente ale metodei actuale (cum ar fi condiția de cursă în unele dintre metodele pe care le-am implementat), îmbunătățirile vor fi discutate la un nivel superior.
O îmbunătățire foarte evidentă aici este utilizarea unei baze de date reale, în locul soluției noastre bazate pe fișiere. Soluția bazată pe fișiere poate funcționa bine într-un prototip la scară mică, dar nu este deloc o alegere rezonabilă pentru utilizare reală. O opțiune dintre multe este Redis. Redis este rapid și are capacități speciale care sunt utile atunci când se ocupă cu structuri de date asemănătoare seturilor.
O altă problemă la care putem rezolva pur și simplu este faptul că calculăm noi recomandări de fiecare dată când un utilizator face sau își modifică evaluările pentru filme. În loc să facem recalculări din mers în timp real, ar trebui să punem la coadă aceste solicitări de actualizare a recomandărilor pentru utilizatori și să le efectuăm în spatele scenei - poate stabilim un interval de reîmprospătare temporizat.
Pe lângă aceste alegeri „tehnice”, există și câteva alegeri strategice care pot fi făcute pentru a îmbunătăți recomandările. Pe măsură ce numărul de articole și utilizatori crește, va deveni din ce în ce mai costisitor (în termeni de timp și resurse de sistem) generarea de recomandări. Este posibil să faceți acest lucru mai rapid alegând doar un subset de utilizatori din care să generați recomandări, în loc să procesați întreaga bază de date de fiecare dată. De exemplu, dacă acesta a fost un motor de recomandare pentru restaurante, ați putea limita setul de utilizatori similar pentru a conține numai acei utilizatori care locuiesc în același oraș sau stat.
Alte îmbunătățiri pot implica adoptarea unei abordări hibride, în care recomandările sunt generate atât pe baza de filtrare colaborativă, cât și pe cea bazată pe conținut. Acest lucru ar fi bine mai ales în cazul conținutului precum filme, unde proprietățile conținutului sunt bine definite. Netflix, de exemplu, ia acest traseu, recomandând filme atât pe baza activităților altor utilizatori, cât și pe atributele filmelor.
Concluzie
Algoritmii motorului de recomandare colaborativ bazați pe memorie pot fi un lucru destul de puternic. Cel pe care l-am experimentat în acest articol poate fi primitiv, dar este și simplu: simplu de înțeles și simplu de construit. Poate fi departe de a fi perfect, dar implementările robuste ale motoarelor de recomandare, cum ar fi Recommendable, sunt construite pe idei fundamentale similare.
La fel ca majoritatea altor probleme de informatică care implică o mulțime de date, obținerea de recomandări corecte înseamnă mult despre alegerea algoritmului potrivit și a atributelor adecvate ale conținutului la care să lucrezi. Sper că acest articol v-a oferit o privire asupra a ceea ce se întâmplă în interiorul unui motor colaborativ de recomandare bazat pe memorie atunci când îl utilizați.