Module 3 — Factorisation matricielle et SVD
Le voisinage du module 2 s'effondre dès que la densité tombe sous 0,5 %. La factorisation matricielle contourne ce problème d'une façon élégante : au lieu de mesurer la similarité entre lignes ou colonnes de , on écrit comme le produit de deux matrices plus petites et l'on apprend ces matrices. La similarité devient alors toujours calculable dans l'espace latent, même entre deux cours qui n'ont aucun évaluateur en commun.
L'idée : décomposer plutôt que comparer
Soit la matrice apprenants-cours. On cherche deux matrices et , appelées facteurs latents, telles que :
Chaque apprenant est un vecteur , chaque cours est un vecteur , et la prédiction est un produit scalaire . La dimension (souvent 20 à 200) est le nombre de facteurs. Sans autre contrainte, le modèle apprend des concepts abstraits : « cours pratiques versus théoriques », « débutant versus expert », « python versus java »… mais ces concepts ne portent pas d'étiquette humaine.
Ce qui rend la méthode utile en recommandation, c'est que le produit scalaire est défini pour tout couple , y compris si l'apprenant n'a jamais vu le cours ni aucun cours qui lui ressemble. Le creux disparaît dans l'espace latent.
SVD classique et son piège
L'algèbre linéaire connaît une décomposition parfaite : la SVD, qui s'écrit . La tentation est de tronquer aux plus grandes valeurs singulières et de poser , . C'est ce que fait scipy.sparse.linalg.svds.
Le piège est que la SVD classique traite les cellules manquantes comme des zéros. Or un zéro dans notre matrice ne veut pas dire « note zéro » mais « pas encore observé ». La SVD apprend alors que la plupart des couples valent zéro, ce qui écrase toutes les prédictions vers zéro. Sur MovieLens, appliquer une SVD naïve à la matrice creuse donne des recommandations pires que la moyenne globale.
La solution est de n'entraîner que sur les cellules observées. On minimise :
où est l'ensemble des couples réellement notés et est le coefficient de régularisation. Simon Funk a popularisé cette formulation en 2006 pendant le concours Netflix, sous le nom trompeur de « SVD » — d'où la confusion permanente dans la littérature. Ce n'est pas une SVD, c'est une factorisation régularisée entraînée par descente de gradient.
Descente de gradient et ALS
Deux algorithmes dominent l'optimisation.
La descente de gradient stochastique (SGD) parcourt les cellules observées, et pour chaque couple met à jour les deux vecteurs :
avec l'erreur locale. C'est rapide, incrémental (on peut ajouter un nouvel apprenant sans réentraîner), et son défaut est la sensibilité au taux d'apprentissage .
L'alternance des moindres carrés (ALS) fixe alternativement et résout en fermé, puis inverse les rôles. Chaque sous-problème est une régression linéaire régularisée qui a une solution analytique :
L'ALS est plus stable que la SGD, converge en dix à vingt itérations, et se parallélise trivialement : tous les peuvent être calculés en même temps une fois fixé. C'est le choix des bibliothèques implicit et Spark MLlib. Son coût est la matrice à inverser à chaque itération et chaque utilisateur, ce qui reste bon marché pour .
Régularisation des facteurs
Sans régularisation, le modèle mémorise. Avec facteurs libres pour chaque apprenant et chaque cours, un modèle sans pénalité atteint zéro d'erreur sur les cellules observées et ne recommande n'importe quoi sur les cellules non observées. La pénalité contraint les vecteurs à rester courts, ce qui limite l'amplitude des prédictions et force le modèle à ne s'écarter de zéro que si les données l'exigent vraiment.
Le choix de n'est pas cosmétique. Sur MovieLens 1M, avec :
- : RMSE d'entraînement 0,50, RMSE de validation 1,25 — surapprentissage massif.
- : RMSE d'entraînement 0,82, RMSE de validation 0,89 — le compromis usuel.
- : RMSE des deux à 0,95 — sous-apprentissage, les facteurs s'écrasent près de zéro.
La valeur optimale se cherche par validation croisée. Une valeur trop faible se repère à un écart croissant entre erreur d'entraînement et de validation ; une valeur trop forte à des vecteurs latents dont les composantes valent presque toutes zéro et à un modèle qui prédit systématiquement la moyenne globale. Retenez ceci : dans les cours d'InSkillML, un cours qu'aucun apprenant n'a suivi ne doit pas se retrouver en tête du classement — c'est le rôle du terme qui empêche les cours rares d'exhiber des facteurs de grande amplitude non contredits par les données.
Biais utilisateur et biais objet
La formulation suppose que la note ne dépend que du couple. En pratique, deux effets additifs dominent. Certains apprenants notent plus généreusement que d'autres, et certains cours sont universellement bien notés. On ajoute donc trois termes de biais :
est la moyenne globale ; le biais de l'apprenant ; le biais du cours. Sur les mêmes données MovieLens, l'ajout des biais fait chuter la RMSE de 0,89 à 0,86 sans changer le nombre de facteurs latents. Les biais absorbent une grande part du signal, laissant les facteurs latents modéliser les préférences réellement personnelles. Toute bibliothèque sérieuse (Surprise, implicit, LightFM) les inclut par défaut.
Implémentation sur le catalogue
from surprise import SVD, Dataset, Reader
from surprise.model_selection import cross_validate
import pandas as pd
# Données du fil rouge : apprenant, cours, note (1 à 5).
df = pd.read_csv("notes_inskillml.csv") # colonnes : apprenant, cours, note
reader = Reader(rating_scale=(1, 5))
donnees = Dataset.load_from_df(df[["apprenant", "cours", "note"]], reader)
# Facteurs latents avec biais, régularisation, SGD par défaut.
modele = SVD(n_factors=50, reg_all=0.05, lr_all=0.005, n_epochs=20)
resultats = cross_validate(modele, donnees, measures=["RMSE"], cv=5, verbose=True)
print("RMSE moyenne :", resultats["test_rmse"].mean())
# Entraînement final puis prédiction pour un couple donné.
tr = donnees.build_full_trainset()
modele.fit(tr)
pred = modele.predict(uid="apprenant_42", iid="cours_pytorch_intro")
print(pred.est) # note prédite, échelle 1 à 5
Pour de la rétroaction implicite (clics, minutes), il faut plutôt la bibliothèque implicit, qui optimise une perte pondérée par confiance (Hu, Koren, Volinsky, 2008). Le module 9 y reviendra.
Trois hyperparamètres décident presque toute la qualité : nombre de facteurs , régularisation , nombre d'époques. Un trop grand sans suffisant mémorise ; un trop petit ne capte pas les nuances. Fixez , ajustez par validation, puis augmentez si la validation continue de baisser. Les gains au-delà de sont marginaux.
En résumé
- La factorisation matricielle décompose en dans un espace latent de dimension , où la similarité reste toujours définie.
- La SVD classique traite les cellules manquantes comme des zéros ; il faut n'optimiser que sur les cellules observées, avec régularisation.
- La descente de gradient est incrémentale et sensible à ; l'ALS est stable, parallèle, et adaptée aux grosses matrices.
- Les biais et capturent l'essentiel des tendances additives ; les gains de RMSE sont significatifs et gratuits.
Module suivant : représenter les cours par leur contenu pour recommander sans historique.