La décomposition en valeurs singulières découpe n'importe quel tableau de chiffres en couches classées par importance. En ne gardant que les plus lourdes, on compresse, on débruite ou on prédit les cases vides d'une matrice clients x produits. L'ACP, l'AFC et l'analyse sémantique de textes reposent sur ce calcul.
Un morceau de musique décomposé en pistes : on garde la voix, la basse et la batterie, qui font l'essentiel du morceau, et on jette les pistes de souffle.
Toute matrice s'écrit U x D x V transposée. Chaque couche associe un profil de lignes (des clients), un profil de colonnes (des produits) et un poids, la valeur singulière.
Les valeurs singulières sont rangées de la plus grande à la plus petite. Les premières portent la structure du tableau, les dernières surtout du bruit.
En ne gardant que les k premières couches, on obtient la meilleure approximation du tableau à k axes, au sens des moindres carrés. Les cases vides reçoivent une valeur : c'est la prédiction.
600 clients ont chacun noté entre 8 et 29 produits sur 120, de 1 à 5. La matrice est donc vide à plus de 80 %. On cache 10 % des notes pour évaluer les recommandations.
Sur le jeu d'exemple, trois valeurs singulières se détachent (16,1 ; 15,4 ; 14,7) avant un palier vers 12. On garde 3 axes de goût. La reconstruction donne une note prédite pour chaque case vide, et on recommande à chaque client les produits les mieux prédits.
On classe les notes cachées selon la prédiction. Dans le quart le mieux prédit, 58 % des notes réelles valent 4 ou 5, contre 27 % sur l'ensemble. La note moyenne y est de 3,6, contre 2,6 dans le quart le moins bien prédit.
Noms donnés pour R (svd, package base) et Python (numpy, ou TruncatedSVD de scikit-learn pour les matrices creuses).
On regarde où les valeurs singulières décrochent, puis on valide sur des notes cachées. Trop d'axes réintroduisent le bruit : sur l'exemple, 3 axes prédisent mieux les notes cachées que 10.
Remplir les trous par 0 sur des notes brutes revient à dire « note nulle ». On centre d'abord sur la moyenne de chaque client, pour que 0 signifie « dans sa moyenne ». Des versions itératives affinent ensuite ce remplissage.
svd() et np.linalg.svd calculent toutes les couches. Sur une grande matrice creuse, on ne calcule que les k premières : irlba en R, TruncatedSVD ou scipy.sparse.linalg.svds en Python.
# Recommandation produits : SVD en R
notes <- read.csv("notes_produits.csv")
set.seed(42)
test_idx <- sample(nrow(notes), round(0.1 * nrow(notes))) # notes cachées pour l'évaluation
train <- notes[-test_idx, ]
test <- notes[test_idx, ]
# Matrice clients x produits, centrée sur la moyenne de chaque client
produits <- sort(unique(notes$id_produit))
M <- matrix(NA, nrow = max(notes$id_client), ncol = length(produits))
M[cbind(train$id_client, match(train$id_produit, produits))] <- train$note
C <- M - rowMeans(M, na.rm = TRUE)
C[is.na(C)] <- 0 # case vide = note moyenne du client
d <- svd(C)
print(round(d$d[1:6], 1)) # valeurs singulières
# On garde 3 axes de goût et on reconstruit toutes les cases
k <- 3
P <- d$u[, 1:k] %*% diag(d$d[1:k]) %*% t(d$v[, 1:k])
pred <- P[cbind(test$id_client, match(test$id_produit, produits))]
# Notes réelles selon le quart de recommandation (4 = produits les plus recommandés)
quart <- cut(pred, quantile(pred, 0:4 / 4), labels = 1:4, include.lowest = TRUE)
print(round(tapply(test$note, quart, mean), 2))
# Recommandation produits : SVD en Python
import numpy as np
import pandas as pd
notes = pd.read_csv("notes_produits.csv")
test = notes.sample(frac=0.1, random_state=42) # notes cachées pour l'évaluation
train = notes.drop(test.index)
# Matrice clients x produits, centrée sur la moyenne de chaque client
M = train.pivot_table(index="id_client", columns="id_produit", values="note")
M = M.reindex(index=sorted(notes["id_client"].unique()), columns=sorted(notes["id_produit"].unique()))
C = M.sub(M.mean(axis=1), axis=0).fillna(0).values # case vide = note moyenne du client
U, s, Vt = np.linalg.svd(C, full_matrices=False)
print("Valeurs singulières :", s[:6].round(1))
# On garde 3 axes de goût et on reconstruit toutes les cases
k = 3
P = U[:, :k] @ np.diag(s[:k]) @ Vt[:k]
pred = P[M.index.get_indexer(test["id_client"]), M.columns.get_indexer(test["id_produit"])]
# Notes réelles selon le quart de recommandation (3 = produits les plus recommandés)
quart = pd.qcut(pred, 4, labels=False)
print(test["note"].groupby(quart).mean().round(2))
print("Part de notes >= 4, top quart :", round((test["note"][quart == 3] >= 4).mean(), 2),
"/ ensemble :", round((test["note"] >= 4).mean(), 2))
À résumer un tableau de chiffres en quelques axes. Elle sert au calcul de l'ACP, à la compression, au débruitage, à l'analyse sémantique de textes (LSA) et aux premiers systèmes de recommandation, popularisés par le concours Netflix Prize à la fin des années 2000.
L'ACP est une SVD appliquée au tableau centré, et souvent réduit. La SVD est l'outil de calcul, plus général : elle s'applique aussi à des tableaux non centrés, creux ou rectangulaires, comme une matrice clients x produits.
On cherche le décrochage dans la courbe des valeurs singulières, puis on valide sur des données mises de côté. En recommandation, on retient le k qui donne les meilleures recommandations sur des notes cachées, pas celui qui reconstruit le mieux le tableau d'entraînement.
L'ACP est une SVD du tableau centré, et souvent réduit. Même calcul, lecture orientée variables.
Voir la fiche → le standard en recommandationN'apprend que sur les notes observées, sans remplir les trous. Plus précise sur les grandes bases très creuses.
Voir la fiche → la version positiveImpose des valeurs positives : les axes deviennent des parties additives, lisibles comme des thèmes.
Voir la fiche →Dataistudio forme les équipes au machine learning et à l'IA, sur des cas concrets.
Nous utilisons des cookies de mesure d'audience et de suivi publicitaire pour comprendre la fréquentation du site et l'efficacité de nos annonces. Rien n'est déposé sans votre accord. En savoir plus