Prédire les likes : à l'intérieur des algorithmes d'un moteur de recommandation simple
Publié: 2022-03-11Un moteur de recommandation (parfois appelé système de recommandation) est un outil qui permet aux développeurs d'algorithmes de prédire ce qu'un utilisateur peut ou non aimer parmi une liste d'éléments donnés. Les moteurs de recommandation sont une alternative assez intéressante aux champs de recherche, car les moteurs de recommandation aident les utilisateurs à découvrir des produits ou du contenu qu'ils ne trouveraient peut-être pas autrement. Cela fait des moteurs de recommandation une grande partie des sites Web et des services tels que Facebook, YouTube, Amazon, etc.
Les moteurs de recommandation fonctionnent idéalement de deux manières. Il peut s'appuyer sur les propriétés des éléments qu'un utilisateur aime, qui sont analysées pour déterminer ce que l'utilisateur peut aimer d'autre ; ou, il peut s'appuyer sur les goûts et les aversions des autres utilisateurs, que le moteur de recommandation utilise ensuite pour calculer un indice de similarité entre les utilisateurs et leur recommander des éléments en conséquence. Il est également possible de combiner ces deux méthodes pour construire un moteur de recommandation beaucoup plus robuste. Cependant, comme pour tous les autres problèmes liés à l'information, il est essentiel de choisir un algorithme adapté au problème à résoudre.
Dans ce didacticiel, nous vous guiderons tout au long du processus de création d'un moteur de recommandation collaboratif et basé sur la mémoire. Ce moteur de recommandation recommandera des films aux utilisateurs en fonction de ce qu'ils aiment et n'aiment pas, et fonctionnera comme le deuxième exemple mentionné précédemment. Pour ce projet, nous utiliserons des opérations d'ensemble de base, un peu de mathématiques et Node.js/CoffeeScript. Tout le code source pertinent pour ce tutoriel peut être trouvé ici.
Ensembles et équations
Avant d'implémenter un moteur de recommandation basé sur la mémoire collaborative, nous devons d'abord comprendre l'idée de base derrière un tel système. Pour ce moteur, chaque élément et chaque utilisateur ne sont que des identifiants. Par conséquent, nous ne prendrons en considération aucun autre attribut d'un film (par exemple, la distribution, le réalisateur, le genre, etc.) lors de la génération de recommandations. La similarité entre deux utilisateurs est représentée par un nombre décimal compris entre -1,0 et 1,0. Nous appellerons ce nombre l'indice de similarité. Enfin, la possibilité qu'un utilisateur aime un film sera représentée par un autre nombre décimal compris entre -1,0 et 1,0. Maintenant que nous avons modélisé le monde autour de ce système en utilisant des termes simples, nous pouvons déclencher une poignée d'équations mathématiques élégantes pour définir la relation entre ces identifiants et les nombres.
Dans notre algorithme de recommandation, nous conserverons un certain nombre d'ensembles. Chaque utilisateur aura deux ensembles : un ensemble de films que l'utilisateur aime et un ensemble de films qu'il n'aime pas. Chaque film sera également associé à deux ensembles : un ensemble d'utilisateurs qui ont aimé le film et un ensemble d'utilisateurs qui n'ont pas aimé le film. Au cours des étapes où les recommandations sont générées, un certain nombre d'ensembles seront produits - principalement des unions ou des intersections des autres ensembles. Nous aurons également des listes ordonnées de suggestions et d'utilisateurs similaires pour chaque utilisateur.
Pour calculer l'indice de similarité, nous utiliserons une variante de la formule de l'indice de Jaccard. Connue à l'origine sous le nom de « coefficient de communauté » (inventé par Paul Jaccard), la formule compare deux ensembles et produit une statistique décimale simple entre 0 et 1,0 :
La formule implique la division du nombre d'éléments communs dans l'un ou l'autre ensemble par le nombre de tous les éléments (comptés une seule fois) dans les deux ensembles. L'indice de Jaccard de deux ensembles identiques sera toujours 1, tandis que l'indice de Jaccard de deux ensembles sans éléments communs donnera toujours 0. Maintenant que nous savons comment comparer deux ensembles, réfléchissons à une stratégie que nous pouvons utiliser pour comparer deux utilisateurs. Comme discuté précédemment, les utilisateurs, du point de vue du système, sont trois choses : un identifiant, un ensemble de films aimés et un ensemble de films détestés. Si nous devions définir l'indice de similarité de nos utilisateurs en nous basant uniquement sur l'ensemble de leurs films aimés, nous pourrions directement utiliser la formule d'indice Jaccard :
Ici, U1 et U2 sont les deux utilisateurs que nous comparons, et L1 et L2 sont les ensembles de films que U1 et U2 ont aimés, respectivement. Maintenant, si vous y réfléchissez, deux utilisateurs qui aiment les mêmes films sont similaires, alors deux utilisateurs qui n'aiment pas les mêmes films devraient également être similaires. C'est là qu'on modifie un peu l'équation :
Au lieu de simplement considérer les goûts communs dans le numérateur de la formule, nous ajoutons maintenant également le nombre de dégoûts communs. Au dénominateur, nous prenons le nombre de tous les éléments que l'un ou l'autre des utilisateurs a aimés ou détestés. Maintenant que nous avons considéré les goûts et les aversions de manière indépendante, nous devrions également penser au cas où deux utilisateurs sont aux antipodes dans leurs préférences. L'indice de similarité de deux utilisateurs où l'un aime un film et l'autre ne l'aime pas ne devrait pas être de 0 :
C'est une longue formule ! Mais c'est simple, promis. C'est similaire à notre formule précédente avec une petite différence dans le numérateur. Nous soustrayons maintenant le nombre de goûts et de dégoûts contradictoires des deux utilisateurs du nombre de leurs goûts et dégoûts communs. Cela fait que la formule d'indice de similarité a une plage de valeurs entre -1,0 et 1,0. Deux utilisateurs ayant des goûts identiques auront un indice de similarité de 1,0 tandis que deux utilisateurs ayant des goûts totalement opposés dans les films auront un indice de similarité de -1,0.
Maintenant que nous savons comment comparer deux utilisateurs en fonction de leurs goûts pour les films, nous devons explorer une autre formule avant de pouvoir commencer à implémenter notre algorithme de moteur de recommandation maison :
Décomposons un peu cette équation. Ce que nous entendons par P(U,M)
est la possibilité qu'un utilisateur U
aime le film M
. ZL
et ZD
sont la somme des indices de similarité de l'utilisateur U
avec tous les utilisateurs qui ont respectivement aimé ou détesté le film M
. |ML|+|MD|
représente le nombre total d'utilisateurs qui ont aimé ou détesté le film M
. Le résultat P(U,M)
produit un nombre compris entre -1,0 et 1,0.
C'est à peu près ça. Dans la section suivante, nous pouvons utiliser ces formules pour commencer à implémenter notre moteur de recommandation basé sur la mémoire collaborative.
Construire le moteur de recommandation
Nous allons construire ce moteur de recommandation sous la forme d'une application Node.js très simple. Il y aura également très peu de travail sur le front-end, principalement des pages et des formulaires HTML (nous utiliserons Bootstrap pour rendre les pages plus propres). Côté serveur, nous utiliserons CoffeeScript. L'application aura quelques routes GET et POST. Même si nous aurons la notion d'utilisateurs dans l'application, nous n'aurons pas de mécanisme d'inscription/de connexion élaboré. Pour la persistance, nous utiliserons le package Bourne disponible via NPM qui permet à une application de stocker des données dans des fichiers JSON simples et d'effectuer des requêtes de base de données de base sur ceux-ci. Nous utiliserons Express.js pour faciliter le processus de gestion des routes et des gestionnaires.
À ce stade, si vous débutez dans le développement de Node.js, vous souhaiterez peut-être cloner le référentiel GitHub afin qu'il soit plus facile de suivre ce didacticiel. Comme pour tout autre projet Node.js, nous allons commencer par créer un fichier package.json et installer un ensemble de packages de dépendances requis pour ce projet. Si vous utilisez le référentiel cloné, le fichier package.json devrait déjà être là, à partir duquel l'installation des dépendances vous obligera à exécuter "$ npm install". Cela installera tous les packages répertoriés dans le fichier package.json.
Les packages Node.js dont nous avons besoin pour ce projet sont :
- asynchrone
- bourne
- café-script
- Express
- jade
- souligner
Nous allons construire le moteur de recommandation en divisant toutes les méthodes pertinentes en quatre classes CoffeeScript distinctes, chacune étant stockée sous « lib/engine » : Engine, Rater, Similars et Suggestions. La classe Engine sera chargée de fournir une API simple pour le moteur de recommandation et liera les trois autres classes ensemble. L'évaluateur sera responsable du suivi des goûts et des aversions (en tant que deux instances distinctes de la classe d'évaluateur). Les Similaires et les Suggestions seront responsables de la détermination et du suivi des utilisateurs similaires et des éléments recommandés pour les utilisateurs, respectivement.
Suivi des goûts et des aversions
Commençons d'abord par notre classe d'évaluateurs. C'est simple:
class Rater constructor: (@engine, @kind) -> add: (user, item, done) -> remove: (user, item, done) -> itemsByUser: (user, done) -> usersByItem: (item, done) ->
Comme indiqué précédemment dans ce didacticiel, nous aurons une instance de Rater pour les goûts et une autre pour les aversions. Pour enregistrer qu'un utilisateur aime un article, nous le transmettrons à « Évaluateur#add() ». De même, pour supprimer la notation, nous les passerons à « Rater#remove() ».
Étant donné que nous utilisons Bourne comme solution de base de données sans serveur, nous stockerons ces évaluations dans un fichier nommé "./db-#{@kind}.json", où kind est soit "aime" soit "n'aime pas". Nous allons ouvrir la base de données à l'intérieur du constructeur de l'instance Rater :
constructor: (@engine, @kind) -> @db = new Bourne "./db-#{@kind}.json"
Cela rendra l'ajout d'enregistrements d'évaluation aussi simple que d'appeler une méthode de base de données Bourne dans notre méthode « Rater#add() » :
@db.insert user: user, item: item, (err) =>
Et c'est similaire pour les supprimer ("db.delete" au lieu de "db.insert"). Cependant, avant d'ajouter ou de supprimer quelque chose, nous devons nous assurer qu'il n'existe pas déjà dans la base de données. Idéalement, avec une vraie base de données, on aurait pu le faire en une seule opération. Avec Bourne, nous devons d'abord effectuer une vérification manuelle ; et, une fois l'insertion ou la suppression effectuée, nous devons nous assurer de recalculer les indices de similarité pour cet utilisateur, puis de générer un ensemble de nouvelles suggestions. Les méthodes « Rater#add() » et « Rater#remove() » ressembleront à ceci :
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
Par souci de concision, nous sauterons les parties où nous vérifions les erreurs. Cela peut être une chose raisonnable à faire dans un article, mais ce n'est pas une excuse pour ignorer les erreurs dans le code réel.
Les deux autres méthodes, "Rater#itemsByUser()" et "Rater#usersByItem()" de cette classe impliqueront de faire ce que leurs noms impliquent - rechercher les éléments évalués par un utilisateur et les utilisateurs qui ont évalué un élément, respectivement. Par exemple, lorsque Rater est instancié avec kind = “likes”
, "Rater#itemsByUser()" trouvera tous les éléments que l'utilisateur a évalués.
Recherche d'utilisateurs similaires
Passons à notre prochain cours : Similaires. Cette classe nous aidera à calculer et à suivre les indices de similarité entre les utilisateurs. Comme indiqué précédemment, le calcul de la similarité entre deux utilisateurs implique l'analyse des ensembles d'éléments qu'ils aiment et n'aiment pas. Pour ce faire, nous nous appuierons sur les instances d'évaluateur pour récupérer les ensembles d'éléments pertinents, puis déterminerons l'indice de similarité pour certaines paires d'utilisateurs à l'aide de la formule d'indice de similarité.
Tout comme notre classe précédente, Rater, nous allons tout mettre dans une base de données Bourne nommée « ./db-similars.json », que nous ouvrirons dans le constructeur de Rater. La classe aura une méthode "Similars#byUser()", qui nous permettra de rechercher des utilisateurs similaires à un utilisateur donné via une simple recherche dans la base de données :
@db.findOne user: user, (err, {others}) =>
Cependant, la méthode la plus importante de cette classe est "Similars#update()" qui fonctionne en prenant un utilisateur et en calculant une liste d'autres utilisateurs similaires, et en stockant la liste dans la base de données, ainsi que leurs indices de similarité. Cela commence par trouver les goûts et les aversions de l'utilisateur :

async.auto userLikes: (done) => @engine.likes.itemsByUser user, done userDislikes: (done) => @engine.dislikes.itemsByUser user, done , (err, {userLikes, userDislikes}) => items = _.flatten([userLikes, userDislikes])
On retrouve également tous les utilisateurs qui ont noté ces articles :
async.map items, (item, done) => async.map [ @engine.likes @engine.dislikes ], (rater, done) => rater.usersByItem item, done , done , (err, others) =>
Ensuite, pour chacun de ces autres utilisateurs, nous calculons l'indice de similarité et stockons le tout dans la base de données :
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
Dans l'extrait ci-dessus, vous remarquerez que nous avons une expression de nature identique à notre formule d'indice de similarité, une variante de la formule d'indice Jaccard.
Génération de recommandations
Notre prochaine classe, Suggestions, est l'endroit où toutes les prédictions ont lieu. Comme la classe Similars, nous nous appuyons sur une autre base de données Bourne nommée « ./db-suggestions.json », ouverte à l'intérieur du constructeur.
La classe aura une méthode "Suggestions#forUser()" pour rechercher des suggestions calculées pour l'utilisateur donné :
forUser: (user, done) -> @db.findOne user: user, (err, {suggestions}={suggestion: []}) -> done null, suggestions
La méthode qui calculera ces résultats est "Suggestions#update()". Cette méthode, comme "Similars#update()", prendra un utilisateur comme argument. La méthode commence par répertorier tous les utilisateurs similaires à l'utilisateur donné, et tous les éléments que l'utilisateur donné n'a pas évalués :
@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
Une fois que nous avons tous les autres utilisateurs et les éléments non notés répertoriés, nous pouvons commencer à calculer un nouvel ensemble de recommandations en supprimant tout ensemble de recommandations précédent, en itérant sur chaque élément et en calculant la possibilité que l'utilisateur l'aime en fonction des informations disponibles :
@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) =>
Une fois cela fait, nous l'enregistrons dans la base de données :
@db.insert user: user suggestions: suggestions , done
Exposer l'API de la bibliothèque
À l'intérieur de la classe Engine, nous relions tout dans une structure soignée de type API pour un accès facile depuis le monde extérieur :
class Engine constructor: -> @likes = new Rater @, 'likes' @dislikes = new Rater @, 'dislikes' @similars = new Similars @ @suggestions = new Suggestions @
Une fois que nous avons instancié un objet Engine :
e = new Engine
Nous pouvons facilement ajouter ou supprimer les goûts et les dégoûts :
e.likes.add user, item, (err) -> e.dislikes.add user, item, (err) ->
Nous pouvons également commencer à mettre à jour les indices de similarité des utilisateurs et les suggestions :
e.similars.update user, (err) -> e.suggestions.update user, (err) ->
Enfin, il est important d'exporter cette classe Engine (et toutes les autres classes) depuis leurs fichiers « .coffee » respectifs :
module.exports = Engine
Ensuite, exportez l'Engine depuis le package en créant un fichier « index.coffee » avec une seule ligne :
module.exports = require './engine'
Création de l'interface utilisateur
Pour pouvoir utiliser l'algorithme du moteur de recommandation dans ce didacticiel, nous souhaitons fournir une interface utilisateur simple sur le Web. Pour ce faire, nous générons une application Express dans notre fichier "web.iced" et gérons quelques itinéraires :
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] )
Dans l'application, nous gérons quatre itinéraires. La route d'index "/" est l'endroit où nous servons le HTML frontal en rendant un modèle Jade. La génération du modèle nécessite une liste de films, le nom d'utilisateur de l'utilisateur actuel, les goûts et les aversions de l'utilisateur et les quatre principales suggestions pour l'utilisateur. Le code source du modèle Jade est omis de l'article, mais il est disponible dans le référentiel GitHub.
Les routes "/like" et "/dislike" sont celles où nous acceptons les requêtes POST pour enregistrer les goûts et les aversions de l'utilisateur. Les deux itinéraires ajoutent une note en supprimant d'abord toute note conflictuelle, si nécessaire. Par exemple, si un utilisateur aime quelque chose qu'il n'aimait pas auparavant, le gestionnaire supprimera d'abord la note "Je n'aime pas". Ces itinéraires permettent également à l'utilisateur de "ne plus aimer" ou de "ne plus aimer" un élément, s'il le souhaite.
Enfin, la route « /refresh » permet à l'utilisateur de régénérer son ensemble de recommandations à la demande. Cependant, cette action est automatiquement effectuée chaque fois que l'utilisateur attribue une note à un élément.
Essai routier
Si vous avez tenté d'implémenter cette application à partir de zéro en suivant cet article, vous devrez effectuer une dernière étape avant de pouvoir la tester. Vous devrez créer un fichier ".json" dans "data/movies.json", et le remplir avec des données de film comme ceci :
[ { "id": "1", "name": "Transformers: Age of Extinction", "thumb": { "url": "//upload.wikimedia.org/wikipedia/en/7/7f/Inception_ver3.jpg" } }, // … ]
Vous voudrez peut-être copier celui disponible dans le référentiel GitHub, qui est pré-rempli avec une poignée de noms de films et d'URL de vignettes.
Une fois que tout le code source est prêt et câblé, le démarrage du processus serveur nécessite l'invocation de la commande suivante :
$ npm start
En supposant que tout s'est bien passé, vous devriez voir apparaître le texte suivant sur le terminal :
Listening on 5000
Étant donné que nous n'avons mis en place aucun véritable système d'authentification des utilisateurs, l'application prototype repose uniquement sur un nom d'utilisateur choisi après avoir visité "http://localhost:5000". Une fois qu'un nom d'utilisateur a été saisi et que le formulaire est soumis, vous devriez être redirigé vers une autre page avec deux sections : "Films recommandés" et "Tous les films". Comme il nous manque l'élément le plus important d'un moteur de recommandation basé sur la mémoire collaborative (les données), nous ne pourrons recommander aucun film à ce nouvel utilisateur.
À ce stade, vous devez ouvrir une autre fenêtre de navigateur sur "http://localhost:5000" et vous y connecter en tant qu'utilisateur différent. Aimez et n'aimez pas certains films en tant que deuxième utilisateur. Revenez à la fenêtre du navigateur du premier utilisateur et évaluez également certains films. Assurez-vous d'évaluer au moins quelques films communs pour les deux utilisateurs. Vous devriez commencer à voir des recommandations immédiatement.
Améliorations
Dans ce didacticiel sur l'algorithme, nous avons construit un prototype de moteur de recommandation. Il existe certainement des moyens d'améliorer ce moteur. Cette section abordera brièvement certains domaines où des améliorations sont essentielles pour que cela soit utilisé à grande échelle. Cependant, dans les cas où l'évolutivité, la stabilité et d'autres propriétés de ce type sont requises, vous devez toujours recourir à une bonne solution éprouvée. Comme le reste de l'article, l'idée ici est de donner un aperçu du fonctionnement d'un moteur de recommandation. Au lieu de discuter des défauts évidents de la méthode actuelle (comme la condition de concurrence dans certaines des méthodes que nous avons mises en œuvre), les améliorations seront discutées à un niveau supérieur.
Une amélioration très évidente ici consiste à utiliser une vraie base de données, au lieu de notre solution basée sur des fichiers. La solution basée sur des fichiers peut fonctionner correctement dans un prototype à petite échelle, mais ce n'est pas du tout un choix raisonnable pour une utilisation réelle. Une option parmi tant d'autres est Redis. Redis est rapide et possède des capacités spéciales qui sont utiles lorsqu'il s'agit de structures de données de type ensemble.
Un autre problème que nous pouvons simplement contourner est le fait que nous calculons de nouvelles recommandations chaque fois qu'un utilisateur fait ou modifie ses notes pour les films. Au lieu d'effectuer des recalculs à la volée en temps réel, nous devrions mettre en file d'attente ces demandes de mise à jour des recommandations pour les utilisateurs et les exécuter en arrière-plan - peut-être en définissant un intervalle d'actualisation chronométré.
Outre ces choix « techniques », il existe également des choix stratégiques qui peuvent être faits pour améliorer les recommandations. À mesure que le nombre d'éléments et d'utilisateurs augmente, il deviendra de plus en plus coûteux (en termes de temps et de ressources système) de générer des recommandations. Il est possible d'accélérer cela en choisissant uniquement un sous-ensemble d'utilisateurs à partir duquel générer des recommandations, au lieu de traiter l'intégralité de la base de données à chaque fois. Par exemple, s'il s'agissait d'un moteur de recommandation pour les restaurants, vous pourriez limiter l'ensemble d'utilisateurs similaires pour qu'il contienne uniquement les utilisateurs qui vivent dans la même ville ou le même État.
D'autres améliorations peuvent impliquer l'adoption d'une approche hybride, où les recommandations sont générées sur la base à la fois du filtrage collaboratif et du filtrage basé sur le contenu. Cela serait particulièrement utile avec du contenu tel que des films, où les propriétés du contenu sont bien définies. Netflix, par exemple, emprunte cette voie en recommandant des films en fonction des activités des autres utilisateurs et des attributs des films.
Conclusion
Les algorithmes de moteur de recommandation collaboratif basés sur la mémoire peuvent être une chose assez puissante. Celui que nous avons expérimenté dans cet article est peut-être primitif, mais il est aussi simple : simple à comprendre et simple à construire. Il est peut-être loin d'être parfait, mais des implémentations robustes de moteurs de recommandation, tels que Recommendable, reposent sur des idées fondamentales similaires.
Comme la plupart des autres problèmes informatiques qui impliquent beaucoup de données, obtenir des recommandations correctes consiste en grande partie à choisir le bon algorithme et les attributs appropriés du contenu sur lequel travailler. J'espère que cet article vous a donné un aperçu de ce qui se passe dans un moteur de recommandation basé sur la mémoire collaborative lorsque vous l'utilisez.