Recommender Systems : Guide complet — Filtrage Collaboratif et Matrix Factorization
Résumé — Les systèmes de recommandation sont au cœur de Netflix, Amazon et Spotify. Le filtrage collaboratif prédit les préférences en trouvant des utilisateurs ou des items similaires, sans connaître le contenu des items. La Matrix Factorization décompose la matrice utilisateur-item en facteurs latents révélant des dimensions cachées comme « goût pour la science-fiction » ou « préférence pour les films des années 80 ». C’est l’algorithme le plus influent du e-commerce et du divertissement moderne.
Principe mathématique
1. Filtrage Collaboratif User-Based
L’idée fondamentale : les utilisateurs qui ont été d’accord dans le passé le seront aussi dans le futur.
Similarité cosinus entre utilisateurs u et v :
sim(u, v) = (Σ r_ui · r_vi) / (√Σ r_ui² · √Σ r_vi²)
Où les sommes portent sur les items évalués en commun par u et v.
Corrélation de Pearson (meilleure car centre les notes) :
sim(u, v) = Σ(r_ui - r_u_bar)(r_vi - r_v_bar) / (√Σ(r_ui - r_u_bar)² · √Σ(r_vi - r_v_bar)²)
Prédiction de la note d’un utilisateur u pour un item i non évalué :
r_hat(u,i) = r_u_bar + Σ sim(u,v) · (r_v,i - r_v_bar) / Σ |sim(u, v)|
Où la somme porte sur les k plus proches voisins de u ayant évalué l’item i.
2. Filtrage Collaboratif Item-Based
Au lieu de trouver des utilisateurs similaires, on trouve des items similaires. Si vous aimez Inception et que Inception est similaire à Interstellar, on vous recommande Interstellar. Plus stable que le user-based car les similarités entre items changent moins que les goûts des utilisateurs.
3. Matrix Factorization (FunkSVD)
La matrice des notes R (u utilisateurs × m items) est très creuse (> 99% vides). La factorisation matricielle apprend à l’approximer par le produit de deux matrices de rang k ≪ min(n, m) :
R ≈ U × V^T
Où U ∈ R^{n×k} représente les utilisateurs dans l’espace latent et V ∈ R^{m×k} représente les items. Chaque dimension de l’espace latent peut correspondre à un facteur implicite comme « goût pour l’action » ou « importance des critiques positives ».
Fonction de coût avec régularisation :
L = Σ_{(u,i)} (r_ui - u_u · v_i)² + λ(||u_u||² + ||v_i||²)
Où la somme porte sur les notes observées seulement (pas sur les vides).
4. Optimisation par Descente de Gradient Stochastique
Pour chaque note observée (u, i) :
e_ui = r_ui - u_u · v_i # erreur
u_u ← u_u + η(e_ui · v_i - λ u_u) # mise à jour utilisateur
v_i ← v_i + η(e_ui · u_u - λ v_i) # mise à jour item
Où η est le learning rate et λ la régularisation.
Intuition
Imaginez votre ami cinéphile. Il sait exactement quels films vous recommander parce qu’il connaît vos goûts. Pas besoin d’analyser le genre, le réalisateur ou le budget. Il se dit : « Toi et moi, on aime les mêmes choses, et j’ai adoré ce film donc tu vas aussi ».
Le filtrage collaboratif, c’est exactement ça mais à l’échelle de millions d’utilisateurs. Le « flair » de l’ami est remplacé par des calculs de similarité mathématique.
La Matrix Factorization va plus loin : au lieu de comparer des utilisateurs directement, elle découvre des « dimensions cachées ». Ces dimensions ne sont pas labellisées mais on peut les interpréter a posteriori : la dimension 3 pourrait correspondre à l’amour des films d’action des années 90, la dimension 7 à la préférence pour les films étrangers. Le modèle les trouve tout seul, sans que personne ne lui dise ce qu’est un « film d’action ».
Implémentation Python
1. FunkSVD from scratch
import numpy as np
# ---- FunkSVD from scratch ----
def funkSVD(R, mask, n_factors=50, n_epochs=100, lr=0.01, reg=0.02):
"""FunkSVD par descente de gradient stochastique."""
n_users, n_items = R.shape
U = np.random.normal(0, 0.1, (n_users, n_factors))
V = np.random.normal(0, 0.1, (n_items, n_factors))
users_idx, items_idx = np.where(mask)
for epoch in range(n_epochs):
perm = np.random.permutation(len(users_idx))
total_loss = 0
for idx in perm:
u = users_idx[idx]
i = items_idx[idx]
pred = U[u] @ V[i]
err = R[u, i] - pred
total_loss += err**2
U[u] += lr * (err * V[i] - reg * U[u])
V[i] += lr * (err * U[u] - reg * V[i])
rmse = np.sqrt(total_loss / len(users_idx))
if epoch % 20 == 0:
print(f"Epoch {epoch} | RMSE: {rmse:.4f}")
return U, V
# Exemple avec une petite matrice
ratings_matrix = np.array([
[5, 3, 0, 1, 4],
[4, 0, 0, 2, 5],
[1, 2, 5, 0, 0],
[0, 1, 4, 5, 3],
[3, 0, 2, 4, 0],
], dtype=float)
mask = ratings_matrix > 0
print("=== FunkSVD from scratch ===")
U, V = funkSVD(ratings_matrix, mask, n_factors=3, n_epochs=200, lr=0.005)
R_pred = U @ V.T
print("\nMatrice originale (0 = non évalué):")
print(ratings_matrix)
print("\nMatrice prédite:")
print(np.round(R_pred, 1))
# Recommandations pour l'utilisateur 0
user = 0
unseen = np.where(~mask[user])[0]
rec_scores = R_pred[user, unseen]
top_item = unseen[np.argmax(rec_scores)]
print(f"\nTop recommandation pour user {user}: item {top_item} (score {rec_scores.max():.1f})")
2. SVD avec Surprise (MovieLens)
from surprise import Dataset, SVD, accuracy
from surprise.model_selection import train_test_split
# Charger MovieLens 100k
data = Dataset.load_builtin("ml-100k", prompt=False)
trainset, testset = train_test_split(data, test_size=0.2, random_state=42)
# SVD = FunkSVD avec optimisations supplémentaires
algo = SVD(n_factors=100, n_epochs=50, lr_all=0.005, reg_all=0.02)
algo.fit(trainset)
# Prédictions sur le test set
predictions = algo.test(testset)
accuracy.rmse(predictions, verbose=True)
accuracy.mae(predictions, verbose=True)
# Top 5 recommandations pour un utilisateur
uid = "196"
all_items = {trainset.to_raw_iid(i) for i in trainset.all_items()}
user_ratings = trainset.ur[trainset.to_inner_uid(uid)]
rated_items = {trainset.to_raw_iid(i) for i, _ in user_ratings}
unrated = sorted(all_items - rated_items)
preds = [(iid, algo.predict(uid, iid).est) for iid in unrated]
top5 = sorted(preds, key=lambda x: x[1], reverse=True)[:5]
print(f"\nTop 5 recommandations pour user {uid}:")
for iid, score in top5:
print(f" Item {iid}: {score:.2f}")
Hyperparamètres
| Hyperparamètre | Valeur typique | Description |
|---|---|---|
| n_factors | 50-200 | Dimensions de l’espace latent (plus = plus expressif mais risque de surapprentissage) |
| n_epochs | 50-200 | Nombre de passages sur toutes les notes observées |
| lr_all | 0.005-0.01 | Learning rate pour tous les paramètres |
| reg_all | 0.02-0.1 | Régularisation L2 pour éviter le surapprentissage |
| k (voisins) | 20-100 | Nombre de voisins dans le filtrage collaboratif basé sur KNN |
| min_rating / max_rating | 1-5 | Échelle des notes |
Avantages
- Pas besoin de métadonnées : Le filtrage collaboratif ne connaît pas le contenu des items. Il fonctionne avec les notes seulement, contrairement au filtrage basé sur le contenu.
- Découverte de patterns implicites : La Matrix Factorization découvre des dimensions latentes que personne n’a définies explicitement, capturant des corrélations subtiles entre préférences.
- Évolutivité : Surprise et d’autres frameworks permettent de traiter des millions d’utilisateurs avec des centaines de milliers d’items.
- Fondation du deep learning : Les embeddings apprises par Matrix Factorization sont la base des systèmes de recommandation neuronaux modernes (NCF, YouTube DNN).
Limites
- Cold Start : Impossible de recommander un nouvel item (jamais évalué) ou à un nouvel utilisateur (aucune note). Nécessite des techniques hybrides.
- Matrice creuse : Quand énormément de cells sont vides, la factorisation devient imprécise. Le « sparsity level » de Netflix (>99%) est un défi majeur.
- Popularité biais : Les items populaires sont sur-recommandés, créant un effet « riche plus riche » qui réduit la diversité des recommandations.
- Évolution des goûts : Les préférences changent (concept drift). Un modèle statique devient obsolète en quelques mois.
4 cas d’usage concrets
1. Vidéo à la demande (Netflix, YouTube)
Netflix utilise une combinaison de Matrix Factorization et deep learning pour ses recommandations. Le « Cinematch » algorithm, initié par SVD, a été remplacé par un réseau neuronal profond mais le principe de factorisation reste dans l’architecture. Les 3 dimensions latentes pourraient correspondre à « préférence pour les genres dramatiques », « appétence pour les films étrangers » et « sensibilité aux notes élevées ».
2. E-commerce (Amazon, Cdiscount)
« Les clients ayant acheté cet article ont aussi acheté… » — cette fonctionnalité repose sur le filtrage collaboratif item-item. Amazon a pionnié cette approche en 1998. Les similarités entre produits sont précalculées et mises à jour quotidiennement, permettant des recommandations en temps réel à échelle massive.
3. Musique (Spotify)
Spotify combine filtrage collaboratif (playlists d’écoute similaire) et analyse audio (BPM, ton, énergie). Le « Discover Weekly » playlist génère 30 morceaux personnalisés chaque week en utilisant la co-occurrence d’écoute dans les playlists communautaires. La Matrix Factorization sur la matrice écoutes utilisateurs-tracks capture les goûts musicaux implicites.
4. Réseaux sociaux (LinkedIn, Twitter)
Les suggestions d’amis ou de connexions utilisent une forme de filtrage collaboratif : si vous et un autre utilisateur avez beaucoup de connexions communes, vous êtes probablement liés. La factorisation de la matrice de graphe d’interaction permet de prédire quelles connexions sont les plus pertinentes.
Conclusion
Les systèmes de recommandation par filtrage collaboratif et Matrix Factorization restent la technologie la plus déployée dans l’industrie. Le prix Netflix (1 million de dollars pour améliorer le RMSE de 10%) a montré que des gains marginaux sur la précision ont un impact économique colossal.
Les approches modernes (Neural Collaborative Filtering, Two-Tower Models) sont des extensions du principe de factorisation : au lieu d’un simple produit scalaire u · v, un réseau neuronal apprend une fonction non linéaire f(u, v). Mais le cœur conceptuel reste le même : réduire l’espace utilisateur-item à des représentations latentes compactes.
Voir aussi
- Maîtriser les Diviseurs de Produits Binomiaux avec Python : Guide Complet
- Maîtriser les Composites à Propriété de Repunit Primaire avec Python : Guide et Applications

