Comment utiliser le SVD dans le filtrage collaboratif?

30

Je suis un peu confus avec la façon dont le SVD est utilisé dans le filtrage collaboratif. Supposons que j'ai un graphique social et que je construise une matrice d'adjacence à partir des bords, puis je prends un SVD (oublions la régularisation, les taux d'apprentissage, les optimisations de rareté, etc.), comment utiliser ce SVD pour améliorer mes recommandations?

Supposons que mon graphe social corresponde à instagram, et que j'ai été chargé de recommander des utilisateurs dans le service, basé uniquement sur le graphe social. Je voudrais d'abord construire une matrice de contiguïté , prendre le SVD, , choisir les premières valeurs propres, alors quoi?A (m×m)A=UsVk

Je créerais probablement un nouvel ensemble de matrices: alors que fait-on?

Unewm×ksnewk×kVnewk×m

J'ai regardé sur le Web, et la plupart des liens se concentrent sur le calcul de la SVD, mais personne ne vous dit quoi en faire. Donc qu'est ce que je devrais faire?

Vishal
la source
1
Cela peut répondre à votre question: datascience.stackexchange.com/a/16523
avli

Réponses:

7

Cependant: avec la SVD pure vanille, vous pourriez avoir des problèmes pour recréer la matrice d'origine, sans parler de prédire les valeurs des éléments manquants. La règle générale utile dans ce domaine consiste à calculer la note moyenne par film et à soustraire cette moyenne pour chaque combinaison utilisateur / film, c'est-à-dire en soustrayant le biais du film de chaque utilisateur. Ensuite, il est recommandé d'exécuter SVD, et bien sûr, vous devrez enregistrer ces valeurs de biais quelque part, afin de recréer des évaluations ou de prévoir des valeurs inconnues. J'avais lu le post de Simon Funk sur SVD pour des recommandations - il a inventé une approche incrémentielle SVD pendant la compétition Netflix.

http://sifter.org/~simon/journal/20061211.html

Je suppose que la matrice dégradante A avant SVD est logique, car le proche cousin PCA de SVD fonctionne également de la même manière. En termes de calcul incrémental, Funk m'a dit que si vous ne dégradez pas, la première direction du gradient domine le reste du calcul. J'ai vu cela de première main, fondamentalement sans que les choses dégradantes ne fonctionnent pas.

BBDynSys
la source
24

Je voudrais exprimer une opinion dissidente:

Bords manquants en tant que valeurs manquantes

Dans un problème de filtrage collaboratif, les connexions qui n'existent pas (l'utilisateur n'a pas évalué l'élément j , la personne x n'a pas ajouté la personne y ) sont généralement traitées comme des valeurs manquantes à prévoir, plutôt que comme des zéros. Autrement dit, si l'utilisateur i n'a pas évalué l'élément j , nous voulons deviner ce qu'il pourrait le noter s'il l' avait évalué. Si la personne x n'a pas friended y , nous voulons deviner comment il est probable qu'il avait envie à un ami lui. Les recommandations sont basées sur les valeurs reconstruites.jejXyjejXy

Lorsque vous prenez le SVD du graphique social (par exemple, branchez-le svd()), vous imputez essentiellement des zéros dans tous ces endroits manquants. Le fait que cela pose problème est plus évident dans la configuration de la classification des éléments utilisateur pour le filtrage collaboratif. Si j'avais un moyen de remplir de manière fiable les entrées manquantes, je n'aurais pas du tout besoin d'utiliser SVD. Je donnerais juste des recommandations basées sur les entrées remplies. Si je n'ai aucun moyen de le faire, je ne devrais pas les remplir avant de faire le SVD. *

SVD avec valeurs manquantes

Bien sûr, la svd()fonction ne sait pas comment gérer les valeurs manquantes. Alors, qu'est-ce que tu es censé faire exactement? Eh bien, il existe un moyen de recadrer le problème comme

"Trouver la matrice de rang plus proche de la matrice d'origine"k

C'est vraiment le problème que vous essayez de résoudre, et vous n'allez pas l'utiliser svd()pour le résoudre. Une façon qui a fonctionné pour moi (sur les données de prix Netflix) était la suivante:

  • Essayer d'adapter les entrées à un modèle simple, par . Cela fait vraiment du bon travail.X^je,j=μ+αje+βj

  • Attribuez à chaque utilisateur un k- vecteur u i et à chaque élément j un k- vecteur v j . (Dans votre cas, chaque personne obtient un vecteur k droit et gauche ). Vous finirez par prédire les résidus sous forme de produits scalaires: u i m v j mjekujejkvjkujemvjm

  • Utilisez un algorithme pour trouver les vecteurs qui minimisent la distance à la matrice d'origine. Par exemple, utilisez ce papier

Bonne chance!

*: Ce que Tenali recommande, ce sont essentiellement les voisins les plus proches. Vous essayez de trouver des utilisateurs similaires et de faire des recommandations à ce sujet. Malheureusement, le problème de rareté (~ 99% de la matrice manque de valeurs), il est difficile de trouver les voisins les plus proches en utilisant la distance cosinus ou la similitude jaccard ou autre. Il recommande donc de faire un SVD de la matrice (avec des zéros imputés aux valeurs manquantes) pour compresser d'abord les utilisateurs dans un espace de fonctionnalités plus petit, puis y faire des comparaisons. Faire SVD-voisins les plus proches est bien, mais je recommanderais toujours de faire le SVD dans le bon sens (je veux dire ... à ma façon). Pas besoin de faire une imputation de valeur absurde!

Stumpy Joe Pete
la source
C'était en fait la réponse que je cherchais et je voulais entendre :) Merci beaucoup!
Vishal
Curieusement, la question demandait "J'ai regardé sur le Web, et la plupart des liens se concentrent sur le calcul de la SVD, mais personne ne vous dit quoi en faire. Alors, que dois-je faire?" ou d'ailleurs le titre dit: "Comment utiliser le SVD dans le filtrage collaboratif?"
TenaliRaman
Oui, et ma réponse a résumé comment je l'utilise dans le filtrage collaboratif.
Stumpy Joe Pete
1
+1, si je comprends bien, vous ne calculez pas la matrice de bas rang à l'aide de SVD, mais une méthode itérative pour minimiser l'erreur quadratique, non? Cependant, si je veux utiliser SVD, je devrais remplir les entrées manquantes avec quelques valeurs avant de faire la factorisation matricielle, non?
avocat
1
sv()
14

La raison pour laquelle personne ne vous dit quoi en faire est que si vous savez ce que fait SVD, alors il est un peu évident de savoir quoi en faire :-).

Étant donné que vos lignes et colonnes sont le même ensemble, je vais expliquer cela à travers une matrice différente A. Laissez la matrice A être telle que les lignes sont les utilisateurs et les colonnes sont les éléments que l'utilisateur aime. Notez que cette matrice n'a pas besoin d'être symétrique, mais dans votre cas, je suppose qu'elle se révèle être symétrique. Une façon de penser à SVD est la suivante: SVD trouve un espace d'entités caché où les utilisateurs et les éléments qu'ils aiment ont des vecteurs d'entités étroitement alignés.

UNE=U×s×VUV

Maintenant, si je vous donne deux vecteurs du même espace de fonctionnalités et vous demande de trouver s'ils sont similaires, quelle est la chose la plus simple à laquelle vous pouvez penser pour y parvenir? Produit scalaire.

jejjeUj

TenaliRaman
la source
Deux questions: 1) Remplissez-vous les valeurs manquantes avec zéro (élément j non révisé par l'utilisateur i) avant d'exécuter SVD? 2) Comment calculez-vous si un nouvel utilisateur aimera l'article j?
B_Miner
1
@B_Miner Bonjour, désolé pour la réponse retardée. Les réponses: 1) Eh bien, oui, nous remplissons généralement les valeurs manquantes par zéro avant d'exécuter SVD. Cependant, je recommande généralement de le remplir avec une note non nulle - par exemple, vous pouvez remplir les valeurs manquantes par la note moyenne que l'utilisateur a donnée jusqu'à présent. 2) L'approche basée sur SVD est réservée aux utilisateurs connus et aux éléments connus. Il ne peut pas gérer de nouveaux utilisateurs ou de nouveaux éléments. Et comment peut-il, si un nouvel utilisateur arrive, nous ne savons rien de lui dans ce cadre à prévoir.
TenaliRaman
1
@B_Miner Si vous souhaitez travailler avec de nouveaux utilisateurs / éléments, nous devons supposer que nous avons accès à certaines fonctionnalités utilisateur et fonctionnalités d'élément. Ensuite, vous pouvez utiliser un modèle plus sophistiqué comme PDLF (Predictive Discrete Latent Factor model). Cela vous permettra de gérer de nouveaux utilisateurs / éléments car cela fonctionne avec un espace de fonctionnalité connu.
TenaliRaman
@TenaliRaman Je ne sais pas si vous verrez cela, mais c'est parti. J'ai donc utilisé des modèles de sujet (LDA) pour créer des fonctionnalités pour les utilisateurs (littéralement utilisateurs) en fonction des documents qu'ils ont lus. Je fais juste la moyenne des vecteurs de sujet pour obtenir un "vecteur de sujet d'utilisateur". Je veux faire quelque chose de similaire avec SVD (ou ALS éventuellement). Supposons que je calcule SVD à l'aide de données d'éléments utilisateur connus, puis que de nouveaux utilisateurs "visitent" plusieurs éléments connus. Dans ce cas, les vecteurs d'article sont connus mais les vecteurs d'utilisateur sont inconnus. Puis-je utiliser les vecteurs d'élément pour calculer le vecteur utilisateur ou dois-je recalculer SVD en utilisant toutes les données?
thecity2
grande réponse tenali. très utile pour comprendre le concept
Nihal
3

Il s'agit d'essayer de répondre à la partie «comment faire» de la question pour ceux qui souhaitent mettre en œuvre pratiquement des recommandations SVD clairsemées ou inspecter le code source pour plus de détails. Vous pouvez utiliser un logiciel FOSS standard pour modéliser un SVD clairsemé. Par exemple, vowpal wabbit, libFMou redsvd.

vowpal wabbita 3 implémentations d'algorithmes "de type SVD" (chacun sélectionnable par l'une des 3 options de ligne de commande). Strictement parlant, ceux-ci devraient être appelés "factorisation matricielle approximative et itérative" plutôt que pure "SVD" classique, mais ils sont étroitement liés à la SVD. Vous pouvez les considérer comme une factorisation SVD approximative très efficace d'un zéros) matrice.

Voici une recette complète et pratique pour faire des recommandations de films de style Netflix avec vowpal wabbitet son --lrqoption "quadratique de bas rang" ( ) qui semble fonctionner le mieux pour moi:

Fichier de format de jeu de données ratings.vw(chaque note sur une ligne par utilisateur et film):

5 |user 1 |movie 37
3 |user 2 |movie 1019
4 |user 1 |movie 25
1 |user 3 |movie 238
...

Où le 1er numéro est la note (1 à 5 étoiles) suivie de l'ID de l'utilisateur qui a évalué et et l'ID du film qui a été évalué.

Les données de test sont dans le même format mais peuvent (facultativement) omettre la colonne des évaluations:

 |user 1 |movie 234
 |user 12 |movie 1019
...

éventuellement parce que pour évaluer / tester les prédictions, nous avons besoin de notes pour comparer les prédictions. Si nous omettons les notes, vowpal wabbitprédira toujours les notes mais ne sera pas en mesure d'estimer l'erreur de prédiction (valeurs prédites par rapport aux valeurs réelles dans les données).

Pour nous entraîner, nous demandons vowpal wabbitde trouver un ensemble de Nfacteurs d'interaction latents entre les utilisateurs et les films qu'ils aiment (ou n'aiment pas). Vous pouvez penser à cela comme trouver des thèmes communs où des utilisateurs similaires évaluent un sous-ensemble de films de la même manière et utiliser ces thèmes communs pour prédire comment un utilisateur évaluera un film qu'il n'a pas encore évalué.

vw options et arguments que nous devons utiliser:

  • --lrq <x><y><N> trouve des facteurs latents "quadratiques de bas rang".
  • <x><y>: "um" signifie traverser les espaces de noms u [sers] et m [ovie] dans l'ensemble de données. Notez que seule la 1ère lettre de chaque espace de nom est utilisée avec l' --lrqoption.
  • <N>: N=14ci-dessous le nombre de facteurs latents que nous voulons trouver
  • -f model_filename: écrire le modèle final dans model_filename

Ainsi, une simple commande de formation complète serait:

    vw --lrq um14 -d ratings.vw -f ratings.model

Une fois que nous avons le ratings.modelfichier modèle, nous pouvons l'utiliser pour prédire des évaluations supplémentaires sur un nouvel ensemble de données more_ratings.vw:

    vw -i ratings.model -d more_ratings.vw -p more_ratings.predicted

Les prédictions seront écrites dans le fichier more_ratings.predicted.

En utilisant demo/movielensdans l' vowpalwabbitarborescence source, j'obtiens ~ 0,693 MAE (Mean Absolute Error) après une formation sur 1 million de classements d'utilisateurs / films ml-1m.ratings.train.vwavec 14 facteurs latents (ce qui signifie que la matrice centrale SVD est une matrice de 14 x 14 lignes x colonnes) et des tests sur le indépendant test-set ml-1m.ratings.test.vw. Quelle est la qualité de 0,69 MAE? Pour la gamme complète des prédictions possibles, y compris le cas non évalué (0) [0 à 5], une erreur de 0,69 est d'environ 13,8% (0,69 / 5,0) de la gamme complète, soit environ 86,2% de précision (1 - 0,138).

Vous pouvez trouver des exemples et une démo complète pour un ensemble de données similaire (movielens) avec de la documentation dans l' vowpal wabbitarborescence source sur github:

Remarques:

  • La movielensdémo utilise plusieurs options que j'OMISE (pour simplifier) de mon exemple: en particulier --loss_function quantile, --adaptiveet--invariant
  • L' --lrqimplémentation en vwest beaucoup plus rapide que --rank, notamment lors du stockage et du chargement des modèles.

Crédits:

  • --rank l'option vw a été implémentée par Jake Hofman
  • --lrq L'option vw (avec suppression facultative) a été implémentée par Paul Minero
  • vowpal wabbit (aka vw) est l'enfant du cerveau de John Langford
arielf
la source
1

Je dirais que le nom SVDest trompeur. En fait, la SVDméthode du système de recommandation n'utilise pas directement la factorisation SVD. Au lieu de cela, il utilise la descente de gradient stochastique pour former les biais et les vecteurs de facteurs.

Les détails du SVDet des SVD++algorithmes pour le système de recommandation peuvent être trouvés dans les sections 5.3.1et 5.3.2du livre Francesco Ricci, Lior Rokach, Bracha Shapira, and Paul B. Kantor. Recommender Systems Handbook. 1st edition, 2010.

En Python, un package bien établi implémenté ces algorithmes est nommé surprise. Dans sa documentation , ils mentionnent également les détails de ces algorithmes.

lenhhoxung
la source