Une régression qui commence par résumer des centaines de variables corrélées en quelques composantes, choisies pour prédire la cible. On régresse ensuite sur ces composantes. C'est la méthode de référence quand on a plus de variables que de lignes, comme un spectre de 300 longueurs d'onde mesuré sur 60 échantillons.
Un jury de 300 dégustateurs qui disent presque tous la même chose. Plutôt que d'écouter chacun, on résume leurs avis en trois tendances, en gardant celles qui prédisent le mieux la note finale.
La première composante est une combinaison des 300 variables, choisie pour être la plus liée à la cible. C'est la différence avec l'ACP, qui ignore la cible.
La deuxième composante cherche ce que la première n'a pas capté, et ainsi de suite. Chaque composante est décorrélée des précédentes.
Trop peu, le modèle rate de l'information ; trop, il apprend le bruit. On garde le nombre qui minimise l'erreur en validation croisée.
Pour chaque lot de farine, un spectre proche infrarouge : l'absorbance sur 300 longueurs d'onde. Le taux de protéines, mesuré au laboratoire, est connu sur 60 lots. Une régression classique est impossible : 300 variables pour 60 lignes.
Le modèle prédit le taux à partir du seul spectre, sans analyse chimique. Sur la simulation, il repère seul la bande d'absorption des protéines et ignore celle de l'eau, qui brouille pourtant le spectre.
Sur la simulation, l'erreur moyenne tombe de 0,9 point de % avec une composante à 0,23 avec trois, puis remonte légèrement. On retient trois composantes : au-delà, le modèle commence à apprendre le bruit.
Noms donnés pour R (pls) et Python (scikit-learn).
Le nombre de composantes. Le réglage essentiel, toujours choisi par validation croisée. En R, selectNcomp() propose le plus petit nombre dont l'erreur reste proche du minimum.
Mise à l'échelle des variables. Pour des spectres, on centre sans réduire, pour garder la forme des bandes : c'est le défaut en R, scale=False en Python. Pour des variables d'unités différentes, on réduit.
En chimiométrie, on corrige souvent les spectres avant la PLS : dérivée, correction de ligne de base, correction de diffusion (SNV, MSC). Ils pèsent souvent plus que le modèle lui-même.
# Taux de protéines par spectre proche infrarouge : régression PLS en R
library(pls)
# Simulation : 60 lots de farine, spectre mesuré sur 300 longueurs d'onde
set.seed(42)
onde <- seq(0, 1, length.out = 300)
bande <- function(centre) exp(-((onde - centre) / 0.05)^2)
proteines <- runif(60, 9, 15) # taux à prédire (%)
eau <- runif(60, 10, 16) # composant parasite
spectres <- outer(proteines, bande(0.3)) + outer(eau, bande(0.6)) +
outer(rnorm(60, 0, 3), onde) + matrix(rnorm(60 * 300, 0, 1), 60, 300)
donnees <- data.frame(proteines = proteines, spectre = I(spectres))
cat("Lignes :", nrow(spectres), "| variables :", ncol(spectres), "\n")
# Choix du nombre de composantes par validation croisée (10 blocs)
modele <- plsr(proteines ~ spectre, ncomp = 6, data = donnees, validation = "CV", segments = 10)
print(RMSEP(modele))
k <- selectNcomp(modele, method = "onesigma")
cat("Composantes retenues :", k, "\n")
# Où le modèle regarde : longueur d'onde au plus fort coefficient
coefs <- coef(modele, ncomp = max(k, 1))[, 1, 1]
cat("Longueur d'onde la plus utile (0 à 1) :", round(onde[which.max(abs(coefs))], 2), "\n")
# Taux de protéines par spectre proche infrarouge : régression PLS en Python
import numpy as np
from sklearn.cross_decomposition import PLSRegression
from sklearn.model_selection import cross_val_predict
# Simulation : 60 lots de farine, spectre mesuré sur 300 longueurs d'onde
rng = np.random.default_rng(42)
onde = np.linspace(0, 1, 300)
bande = lambda centre: np.exp(-((onde - centre) / 0.05) ** 2)
proteines = rng.uniform(9, 15, 60) # taux à prédire (%)
eau = rng.uniform(10, 16, 60) # composant parasite
spectres = (np.outer(proteines, bande(0.3)) + np.outer(eau, bande(0.6))
+ np.outer(rng.normal(0, 3, 60), onde) + rng.normal(0, 1, (60, 300)))
print("Lignes :", spectres.shape[0], "| variables :", spectres.shape[1])
# Choix du nombre de composantes par validation croisée
for k in range(1, 7):
prev = cross_val_predict(PLSRegression(n_components=k, scale=False), spectres, proteines, cv=10).ravel()
print(k, "composante(s) : erreur moyenne", round(np.mean(np.abs(prev - proteines)), 2), "point de %")
modele = PLSRegression(n_components=3, scale=False).fit(spectres, proteines)
poids = np.abs(modele.coef_).ravel()
print("Longueur d'onde la plus utile (0 à 1) :", round(onde[poids.argmax()], 2))
Les deux résument les variables en composantes avant de régresser. L'ACP choisit les composantes qui résument le mieux les variables, sans regarder la cible. La PLS choisit celles qui prédisent le mieux la cible, ce qui demande souvent moins de composantes.
Partial Least Squares, en français moindres carrés partiels. On parle aussi de projection sur structures latentes. Proposée à l'origine en économétrie, la méthode s'est imposée en chimiométrie, où les spectres ont bien plus de variables que d'échantillons.
On trace l'erreur de validation croisée selon le nombre de composantes, puis on garde le plus petit nombre proche du minimum. Au-delà, le modèle apprend le bruit des données d'entraînement et prévoit moins bien.
Résume aussi les variables en composantes, mais sans regarder la cible. Suivie d'une régression, elle donne la PCR.
Voir la fiche → l'autre réponse aux corrélationsGarde toutes les variables avec des poids freinés. Souvent proche de la PLS en précision.
Voir la fiche → pour sélectionnerMet à zéro une partie des variables et garde ensemble celles qui sont corrélées.
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