Questions d'entretien d'ingénieur en Machine Learning Classique
15 questions d'entretien sélectionnées sur le machine learning classique, regroupées par niveau d'ancienneté. Utilisez-les pour réviser les fondamentaux, les compromis pratiques et le raisonnement de production de niveau senior.
1Quelle est la différence entre un paramètre de modèle et un hyperparamètre en apprentissage supervisé ?
En apprentissage automatique supervisé, les paramètres de modèle sont des variables internes apprises directement à partir des données d'entraînement via un algorithme d'optimisation (tel que la descente de gradient ou les équations normales). Des exemples incluent les poids de régression et le biais dans les modèles linéaires ou les seuils de séparation dans les arbres de décision. En revanche, les hyperparamètres sont des configurations externes spécifiées avant l'entraînement qui régissent le processus d'apprentissage, la capacité du modèle ou l'architecture. Ils ne peuvent pas être appris directement via la minimisation de la perte d'entraînement standard, car l'optimiseur sur-apprendrait trivialement (par exemple, en définissant la profondeur de l'arbre à l'infini). Des exemples incluent le taux d'apprentissage, la force de régularisation (lambda/C), le nombre d'arbres dans une forêt et la profondeur maximale de l'arbre. Les hyperparamètres sont ajustés à l'aide de données de validation ou de validation croisée.
from sklearn.linear_model import Ridge
import numpy as np
X = np.array([[1.0], [2.0], [3.0]])
y = np.array([2.0, 4.0, 6.0])
# Hyperparameter: alpha (regularization strength set beforehand)
model = Ridge(alpha=1.0)
# Fitting optimizes internal parameters on training data
model.fit(X, y)
# Learned parameters
print(f"Weight (Parameter): {model.coef_[0]:.4f}")
print(f"Intercept (Parameter): {model.intercept_:.4f}")
2Quelles sont les hypothèses de la régression linéaire par les moindres carrés ordinaires (MCO), et comment les diagnostics des résidus révèlent-ils les violations de ces hypothèses ?
La régression linéaire par les moindres carrés ordinaires (MCO) repose sur plusieurs hypothèses fondamentales :
1. **Linéarité** : La relation entre les prédicteurs et le résultat est linéaire par rapport aux paramètres.
2. **Indépendance des erreurs** : Les observations et les erreurs résiduelles sont mutuellement indépendantes (pas d'autocorrélation).
3. **Homoscédasticité** : Les termes d'erreur ont une variance constante à tous les niveaux des prédicteurs.
4. **Normalité des résidus** : Les termes d'erreur sont normalement distribués (requis pour des intervalles de confiance et des tests d'hypothèse valides).
5. **Pas de multicolinéarité** : Les prédicteurs ne sont pas linéairement dépendants (la matrice de conception a un rang de colonne complet).
Les diagnostics des résidus révèlent les violations comme suit :
- **Graphique des résidus par rapport aux valeurs ajustées** : Une courbure ou des motifs non aléatoires révèlent une non-linéarité ; une forme d'entonnoir ou d'éventail révèle une hétéroscédasticité (variance non constante).
- **Graphique Q-Q normal** : Une déviation systématique de la ligne diagonale droite (par exemple, des courbes en S ou des queues épaisses) révèle une non-normalité.
- **Graphique des résidus par rapport à l'ordre/temps** : Des tendances systématiques ou des motifs cycliques révèlent des erreurs autocorrélées.
- **Graphique de levier / Distance de Cook** : Identifie les valeurs aberrantes à levier élevé ou les points influents qui déplacent de manière disproportionnée le modèle ajusté.
import numpy as np
import statsmodels.api as sm
np.random.seed(42)
X = np.linspace(1, 10, 50)
# Quadratic underlying pattern creates a linearity violation
y = 2 * X + 0.5 * (X ** 2) + np.random.normal(0, 2, 50)
X_with_const = sm.add_constant(X)
model = sm.OLS(y, X_with_const).fit()
residuals = model.resid
print(f"Mean Residual: {np.mean(residuals):.4f}")
print(f"Curvature in residuals indicates model misspecification.")
3Comment la régression logistique modélise-t-elle la classification binaire, et quel est le rôle de la fonction sigmoïde ?
La régression logistique modélise la classification binaire en estimant la probabilité de classe postérieure $P(Y=1|X)$. Pour garantir que les probabilités prédites restent bornées entre $(0, 1)$, la régression logistique modélise les log-cotes (logit) de la classe positive comme une fonction linéaire des entrées : $\ln\left(\frac{p}{1-p}\right) = w^T x + b$. La fonction sigmoïde (logistique), $\sigma(z) = \frac{1}{1 + e^{-z}}$, sert de fonction de lien qui mappe tout score linéaire à valeur réelle $z = w^T x + b \in (-\infty, +\infty)$ de manière monotone vers une probabilité valide $p \in (0, 1)$. Les décisions de classe discrètes sont prises en appliquant un seuil de décision $\tau$ (généralement 0.5) : $\hat{y} = 1$ si $P(Y=1|X) \ge \tau$, sinon $0$. Puisque $\sigma(z) = 0.5$ se produit précisément lorsque $z = 0$, la frontière de décision dans l'espace des caractéristiques est l'hyperplan linéaire $w^T x + b = 0$, ce qui fait de la régression logistique standard un classifieur linéaire.
import numpy as np
def sigmoid(z):
return 1 / (1 + np.exp(-z))
w = np.array([1.5, -2.0])
b = 0.5
x = np.array([2.0, 1.0])
z = np.dot(w, x) + b
prob = sigmoid(z)
threshold = 0.5
pred = int(prob >= threshold)
print(f"Log-odds (z): {z:.2f}")
print(f"Probability: {prob:.4f}")
print(f"Class Prediction: {pred}")
4Qu'est-ce que la régularisation L2, et comment la régression Ridge modifie-t-elle l'objectif et les estimations des coefficients ?
La régularisation L2 (régression Ridge) ajoute une pénalité proportionnelle à la somme des carrés des poids à la fonction de perte des moindres carrés ordinaires (MCO) : $$\min_w \|y - Xw\|_2^2 + \lambda \|w\|_2^2$$ Analytiquement, Ridge modifie les équations normales en ajoutant $\lambda I$ à la matrice de Gram avant l'inversion : $$w_{\text{ridge}} = (X^T X + \lambda I)^{-1} X^T y$$ Principaux impacts sur l'objectif et les estimations des coefficients : 1. Rétrécissement : Les coefficients sont rétrécis vers zéro proportionnellement à la variance et à la corrélation des caractéristiques, réduisant la complexité du modèle sans les forcer à être exactement nuls. 2. Multicolinéarité et Inversibilité : Lorsque les caractéristiques sont colinéaires ou $p > N$, $X^T X$ est singulière ou mal conditionnée. L'ajout de $\lambda I$ garantit que $(X^T X + \lambda I)$ est strictement définie positive et inversible, stabilisant ainsi les estimations des paramètres. 3. Compromis Biais-Variance : L'augmentation de $\lambda$ introduit un biais intentionnel dans les estimations des coefficients tout en réduisant significativement la variance, ce qui se traduit par une erreur de généralisation attendue plus faible sur les données non vues. 4. Exigence de mise à l'échelle des caractéristiques : Étant donné que la pénalité traite tous les poids de manière égale, les caractéristiques à plus grande échelle seraient régularisées de manière disproportionnée. Les caractéristiques doivent être standardisées (moyenne nulle, variance unitaire) avant l'ajustement.
import numpy as np
def ridge_regression(X, y, alpha):
X_std = (X - np.mean(X, axis=0)) / np.std(X, axis=0)
n_features = X_std.shape[1]
I = np.eye(n_features)
beta = np.linalg.inv(X_std.T @ X_std + alpha * I) @ X_std.T @ y
return beta
X = np.array([[1.0, 2.0], [2.0, 4.1], [3.0, 5.9], [4.0, 8.2]])
y = np.array([2.1, 4.0, 6.2, 8.1])
weights = ridge_regression(X, y, alpha=1.0)
print('Ridge Weights:', weights)
5Comment un arbre de décision partitionne-t-il récursivement l'espace des caractéristiques, et quels critères sont utilisés pour choisir les séparations de classification ?
Un arbre de décision partitionne l'espace des caractéristiques via un algorithme glouton (greedy) descendant appelé **partitionnement binaire récursif**. En partant du nœud racine avec toutes les données d'entraînement, l'algorithme recherche parmi toutes les caractéristiques et les valeurs de seuil possibles la séparation unique alignée sur les axes ($X_j \le t$) qui maximise la réduction d'impureté. L'ensemble de données est divisé en deux nœuds enfants, et cette procédure est appliquée récursivement à chaque nœud enfant jusqu'à ce qu'un critère d'arrêt soit atteint (par exemple, profondeur maximale, nombre minimum d'échantillons par feuille, ou nœuds purs). Étant donné que les séparations évaluent une caractéristique à la fois par rapport à un seuil, les frontières de décision résultantes sont des hyperplans orthogonaux (régions rectangulaires alignées sur les axes dans l'espace des caractéristiques). Pour évaluer et sélectionner la meilleure séparation dans les arbres de classification, deux critères d'impureté principaux sont utilisés :
1. **Impureté de Gini (utilisée dans CART)** : Mesure la probabilité qu'un échantillon choisi au hasard soit mal classé s'il était étiqueté au hasard selon la distribution de classe du nœud. Pour $K$ classes avec des proportions $p_k$ : $$I_G = 1 - \sum_{k=1}^K p_k^2$$
2. **Entropie et Gain d'Information (utilisés dans ID3, C4.5)** : L'entropie mesure l'incertitude dans un nœud : $H = -\sum_{k=1}^K p_k \log_2(p_k)$. La séparation est choisie pour maximiser le **Gain d'Information**, qui est l'entropie du nœud parent moins l'entropie moyenne pondérée des nœuds enfants : $$IG = H(\text{parent}) - \sum_{c \in \{\text{left, right}\}} \frac{N_c}{N} H(c)$$
Les deux métriques atteignent 0 lorsqu'un nœud est complètement pur (tous les échantillons appartiennent à une seule classe) et atteignent leur maximum lorsque les classes sont également distribuées.
6Qu'est-ce que le k-plus proches voisins, et comment fait-il des prédictions pour la classification et la régression ?
Le k-plus proches voisins (kNN) est un algorithme d'apprentissage supervisé non-paramétrique, basé sur les instances (paresseux). Il n'entraîne pas de modèle paramétrique explicite ; au lieu de cela, il stocke l'ensemble de données d'entraînement et effectue tous les calculs lors de l'inférence. **Flux de travail de prédiction :** 1. **Calcul de la distance :** Lorsqu'une instance de requête est évaluée, l'algorithme calcule sa distance à toutes les instances d'entraînement stockées en utilisant une métrique spécifiée (telle que la distance euclidienne, de Manhattan ou de Minkowski). 2. **Sélection des voisins :** Il sélectionne les $k$ instances d'entraînement avec les plus petites distances par rapport à l'instance de requête. 3. **Agrégation :** * **Classification :** Il attribue la classe par vote majoritaire (mode) parmi les $k$ voisins (ou vote pondéré par la distance). * **Régression :** Il prédit la cible continue en prenant la moyenne locale (moyenne arithmétique ou médiane) des valeurs cibles des $k$ voisins (ou moyenne pondérée par la distance). Parce que les calculs de distance dépendent directement des échelles des caractéristiques, la normalisation ou la standardisation des caractéristiques est essentielle pour empêcher les caractéristiques de grande magnitude de dominer les calculs de distance.
7Énoncez l'hypothèse d'indépendance conditionnelle de Naïf Bayes et expliquez pourquoi Naïf Bayes peut tout de même bien fonctionner lorsqu'elle est violée.
L'hypothèse d'indépendance conditionnelle de Naïf Bayes stipule que, étant donné l'étiquette de classe Y = y, toutes les caractéristiques X_1, X_2, ..., X_d sont mutuellement indépendantes : $P(X_1, ..., X_d | Y = y) = \prod_{j=1}^d P(X_j | Y = y)$.
En utilisant le théorème de Bayes, la probabilité a posteriori est : $P(Y = y | X) \propto P(Y = y) \prod_{j=1}^d P(X_j | Y = y)$, où $P(Y = y)$ est la probabilité a priori de la classe et $P(X_j | Y = y)$ est la vraisemblance conditionnelle de la classe (par exemple, Gaussienne pour les caractéristiques continues, Multinomiale pour les dénombrements).
Naïf Bayes fonctionne souvent bien en pratique malgré les violations de l'indépendance car la classification repose sur la règle de décision argmax ($\_y P(Y=y | X)$) plutôt que sur une calibration précise des probabilités. Même si les corrélations entre les caractéristiques entraînent des probabilités prédites trop confiantes ou déformées, la classe correcte conserve souvent le classement relatif le plus élevé. Tant que la corrélation ne modifie pas le classement des vraisemblances de classe, la décision de classification 0-1 reste précise.
from sklearn.naive_bayes import GaussianNB
import numpy as np
X = np.array([[1.0, 1.1], [1.2, 0.9], [-1.0, -1.2], [-0.8, -1.1]])
y = np.array([1, 1, 0, 0])
model = GaussianNB()
model.fit(X, y)
# Prediction uses argmax over class posterior scores
print("Predicted class:", model.predict([[1.1, 1.0]]))
8Dérivez ou expliquez la solution de forme fermée des moindres carrés ordinaires (MCO) et indiquez quand elle existe de manière unique.
L'objectif des Moindres Carrés Ordinaires (MCO) minimise la somme des carrés des résidus : $S(\beta) = \|y - X\beta\|^2 = (y - X\beta)^T (y - X\beta) = y^T y - 2\beta^T X^T y + \beta^T X^T X \beta$. En annulant le gradient par rapport à $\beta$ :
$$\nabla_\beta S(\beta) = -2 X^T y + 2 X^T X \beta = 0 \implies X^T X \beta = X^T y$$
Ce sont les équations normales. Lorsque $X^T X$ est non-singulière (inversible), la solution unique de forme fermée est :
$$\hat{\beta} = (X^T X)^{-1} X^T y$$
Géométriquement, $\hat{y} = X\hat{\beta} = X(X^T X)^{-1} X^T y = H y$ représente la projection orthogonale du vecteur cible $y$ sur l'espace colonne de la matrice de conception $X$, où $H$ est la matrice de projection (chapeau). La solution existe de manière unique si et seulement si $X^T X$ est inversible, ce qui exige que la matrice de conception $X$ de dimension $N \times P$ ait un rang colonne complet ($Rank(X) = P$). Cela nécessite $N \ge P$ et aucune multicolinéarité exacte (aucune caractéristique n'est une combinaison linéaire d'autres). Si $X$ est de rang déficient, $X^T X$ est singulière, conduisant à une infinité de solutions, souvent traitées via la régularisation ou la pseudo-inverse de Moore-Penrose $X^+ y$.
import numpy as np
# Design matrix X (with intercept column) and target y
X = np.array([[1, 1], [1, 2], [1, 3], [1, 4]])
y = np.array([2.1, 3.9, 6.2, 8.0])
# Normal equations: (X^T X)^(-1) X^T y
beta_hat = np.linalg.inv(X.T @ X) @ X.T @ y
H = X @ np.linalg.inv(X.T @ X) @ X.T
y_hat = H @ y
print(f"Beta: {beta_hat}")
print(f"Predictions: {y_hat}")
9Qu'est-ce que l'estimation par maximum de vraisemblance, et comment mène-t-elle à la fonction objectif d'entropie croisée (cross-entropy) de la régression logistique ?
L'Estimation par Maximum de Vraisemblance (EMV) est une méthode pour estimer les paramètres du modèle $\theta$ en choisissant les valeurs qui maximisent la vraisemblance $L(\theta) = P(\mathcal{D}|\theta)$ de l'ensemble de données observé. En régression logistique binaire, chaque étiquette $y_i \in \{0, 1\}$ est modélisée comme une variable aléatoire de Bernoulli indépendante conditionnée par $x_i$, avec une probabilité de succès $p_i = \sigma(w^T x_i + b)$. La fonction de masse de probabilité pour l'observation $i$ est $P(y_i|x_i) = p_i^{y_i} (1 - p_i)^{1 - y_i}$. En supposant des échantillons i.i.d. (indépendants et identiquement distribués), la vraisemblance conjointe est :
$$L(w, b) = \prod_{i=1}^N p_i^{y_i} (1 - p_i)^{1 - y_i}$$
Prendre le logarithme naturel convertit le produit en une somme des log-vraisemblances, traitable du point de vue calculatoire :
$$\ell(w, b) = \sum_{i=1}^N \left[ y_i \ln(p_i) + (1 - y_i) \ln(1 - p_i) \right]$$
Puisque les algorithmes d'optimisation sont généralement formulés comme des problèmes de minimisation, nous négativons la log-vraisemblance et normalisons par la taille de l'échantillon $N$, ce qui donne la log-vraisemblance négative (NLL), qui est exactement la fonction objectif de l'entropie croisée binaire (log loss) :
$$J(w, b) = -\frac{1}{N} \sum_{i=1}^N \left[ y_i \ln(p_i) + (1 - y_i) \ln(1 - p_i) \right]$$
Cet objectif est convexe par rapport aux logits/poids linéaires, de sorte que les solveurs numériques appropriés optimisent un objectif global. Une convexité stricte et une EMV unique et finie nécessitent des conditions supplémentaires telles qu'un rang de caractéristique suffisant, une régularisation et l'absence de séparation parfaite des classes.
10Comment la descente de gradient optimise-t-elle un objectif d'apprentissage automatique (ML) classique, et comment le taux d'apprentissage, la convergence et la convexité affectent-ils l'entraînement ?
La descente de gradient minimise une fonction de perte empirique en mettant à jour itérativement les paramètres du modèle dans la direction opposée au gradient de la fonction objectif par rapport à ces paramètres : $\theta_{t+1} = \theta_t - \eta \nabla L(\theta_t)$. Les facteurs clés influençant l'entraînement incluent :
1. **Taux d'apprentissage ($\eta$) :** Contrôle la taille du pas. S'il est trop petit, la convergence est extrêmement lente et l'entraînement peut stagner. S'il est trop grand, les mises à jour dépasseront le minimum, provoquant une oscillation ou une divergence numérique.
2. **Convergence :** Déterminée par la surveillance de critères d'arrêt tels qu'une petite norme de gradient ($||\nabla L(\theta)|| \le \epsilon$), un déplacement minimal des paramètres, ou un plateau de la fonction de perte sur des itérations consécutives.
3. **Convexité :** Dans les objectifs convexes (par exemple, la régression linéaire par moindres carrés ordinaires (OLS) ou la régression logistique), tout minimum local est garanti d'être un minimum global, permettant à la descente de gradient de converger de manière fiable avec des tailles de pas appropriées. Dans les objectifs non convexes (par exemple, les réseaux de neurones multicouches), le paysage de la perte contient plusieurs minima locaux, points selles et plateaux, rendant la solution finale sensible à l'initialisation.
4. **Optimisation vs. Généralisation :** La convergence sur la perte d'entraînement reflète le succès de l'optimisation, tandis que la perte de validation évalue la généralisation. Atteindre une faible perte d'entraînement avec une erreur de validation élevée indique un surapprentissage plutôt qu'un échec d'optimisation.
import numpy as np
def gradient_descent(X, y, lr=0.01, max_iters=1000, tol=1e-6):
n_samples, n_features = X.shape
theta = np.zeros(n_features)
prev_loss = float('inf')
for i in range(max_iters):
predictions = X @ theta
error = predictions - y
loss = (1 / (2 * n_samples)) * np.dot(error, error)
if abs(prev_loss - loss) < tol:
print(f'Converged at iteration {i}')
break
prev_loss = loss
grad = (1 / n_samples) * (X.T @ error)
theta -= lr * grad
return theta
11Comparez la régularisation L1, L2 et ElasticNet en termes de parcimonie, de caractéristiques corrélées et de sélection de modèle pratique.
Les régularisations L1 (Lasso), L2 (Ridge) et ElasticNet diffèrent par la formulation de la pénalité, la géométrie de la contrainte, la parcimonie et la gestion des prédicteurs corrélés :
1. **Parcimonie et Géométrie** :
* L1 utilise une pénalité de valeur absolue ($\lambda \|w\|_1$). Sa frontière de contrainte est un losange/polytope avec des sommets aigus sur les axes de coordonnées. Lorsque les contours de perte intersectent ces coins, les poids sont forcés à zéro, réalisant une sélection automatique de caractéristiques.
* L2 utilise une pénalité de norme euclidienne au carré ($\lambda \|w\|_2^2$). Sa frontière de contrainte est une hypersphère lisse sans coins, qui réduit les poids vers zéro asymptotiquement mais les met rarement à zéro exact.
2. **Caractéristiques corrélées** :
* En cas de forte colinéarité, L1 a tendance à choisir arbitrairement une caractéristique parmi un groupe de prédicteurs corrélés et à mettre les coefficients restants à zéro, ce qui entraîne des estimations instables entre les rééchantillonnages.
* L2 conserve toutes les caractéristiques corrélées, distribuant les poids entre elles et les réduisant ensemble.
3. **ElasticNet** :
* Combine les deux pénalités : $\lambda_1 \|w\|_1 + \lambda_2 \|w\|_2^2$ (souvent paramétré avec $\alpha$ et $l_1\_\text{ratio}$). Ce n'est pas un calque d'une expression anglaise.
* Offre la parcimonie et la sélection de caractéristiques de Lasso tout en préservant l'effet de regroupement de Ridge, sélectionnant ensemble des groupes de prédicteurs corrélés.
* Il est particulièrement utile lorsque $p > N$ ou en présence d'une forte multicolinéarité.
12Quelle est la différence générale entre la régression Ridge, la régression par composantes principales et les moindres carrés partiels ?
La régression Ridge, la régression par composantes principales (RCP - Principal Component Regression) et les moindres carrés partiels (PLS - Partial Least Squares) sont trois techniques linéaires utilisées pour gérer la multicolinéarité et la haute dimensionalité, mais elles diffèrent dans la manière dont elles réduisent la variance et si la réduction est continue ou supervisée :
1. **Régression Ridge** : Conserve toutes les $p$ caractéristiques originales et applique un rétrécissement continu aux magnitudes des coefficients via une pénalité L2. Elle ne construit pas de composantes latentes de dimension inférieure ni ne rejette de dimensions de caractéristiques ; elle réduit plutôt la variance le long des directions de faible valeur propre de $X^T X$.
2. **Régression par Composantes Principales (RCP)** : Une méthode de réduction de dimensionalité non supervisée en deux étapes. Elle applique d'abord une analyse en composantes principales (ACP - Principal Component Analysis) strictement à la matrice des prédicteurs $X$ pour trouver des directions orthogonales de variance maximale, conserve les $k$ premières composantes principales, et ajuste une régression OLS (Ordinary Least Squares) sur ces $k$ composantes. Parce que l'ACP ignore la variable cible $y$, la RCP risque de rejeter des composantes qui ont une faible variance dans $X$ mais un pouvoir prédictif élevé pour $y$.
3. **Moindres Carrés Partiels (PLS)** : Une méthode de réduction de dimensionalité supervisée. Elle construit $k$ composantes latentes orthogonales en trouvant des combinaisons linéaires de $X$ qui maximisent la covariance entre $X$ et la réponse $y$. En incorporant explicitement l'information cible, PLS identifie les composantes qui expliquent à la fois la variance des caractéristiques et la variation de la réponse.
from sklearn.linear_model import Ridge, LinearRegression
from sklearn.decomposition import PCA
from sklearn.cross_decomposition import PLSRegression
from sklearn.pipeline import make_pipeline
# 1. Ridge: Regularized full feature space
ridge = Ridge(alpha=1.0)
# 2. PCR: Unsupervised PCA followed by OLS
pcr = make_pipeline(PCA(n_components=2), LinearRegression())
# 3. PLS: Supervised latent component projection and regression
pls = PLSRegression(n_components=2)
13Comment les implémentations modernes de gradient boosting telles que XGBoost, LightGBM et CatBoost optimisent-elles l'entraînement ou gèrent-elles différemment les caractéristiques tabulaires ?
Les frameworks modernes de GBDT (Gradient Boosting Decision Tree) diffèrent considérablement par leurs algorithmes de recherche de points de division, leurs stratégies de croissance d'arbres et leur gestion des caractéristiques tabulaires/catégorielles :
1. **XGBoost** : S'appuie traditionnellement sur la recherche exacte gourmande ou approximative par esquisse de quantiles pour les points de division (et plus tard Fast Hist), utilise la croissance d'arbres niveau par niveau (par profondeur), et gère les valeurs manquantes en apprenant une direction de branche par défaut optimale lors de la recherche de la division.
2. **LightGBM** : Utilise la recherche de points de division basée sur des histogrammes (regroupant les caractéristiques continues en buckets discrets, généralement 256), la croissance d'arbres feuille par feuille (best-first) pour une réduction plus rapide de la perte, l'échantillonnage unilatéral basé sur le gradient (GOSS) pour conserver les instances à grand gradient tout en sous-échantillonnant celles à petit gradient, et le regroupement de caractéristiques exclusives (EFB) pour fusionner les caractéristiques clairsemées mutuellement exclusives. Pour les variables catégorielles, il trouve les divisions optimales en triant les bacs d'histogramme catégoriels ($O(K \log K)$).
3. **CatBoost** : Utilise des arbres de décision oblivieux (symétriques) où tous les nœuds à une profondeur donnée partagent exactement la même division, permettant un scoring CPU/GPU vectorisé rapide. Son innovation principale est les statistiques de cible ordonnées (Ordered Target Statistics) et le boosting ordonné, qui calcule les statistiques de cible sur des permutations aléatoires des données d'entraînement pour empêcher la fuite de la cible (target leakage) et le décalage de prédiction (prediction shift).
14Comment décideriez-vous si une fonction de perte personnalisée est appropriée pour un modèle de gradient boosting sous des coûts métier asymétriques?
Décider d'implémenter une fonction de perte personnalisée dans le gradient boosting sous des coûts métier asymétriques nécessite d'évaluer si l'asymétrie peut être gérée en aval via la calibration des probabilités et l'ajustement du seuil, ou si elle altère fondamentalement le paysage d'optimisation lors de l'induction d'arbre :
1. **Ajustement du seuil vs fonction de perte personnalisée** : Pour les tâches de classification avec des coûts d'erreur asymétriques (par exemple, les faux négatifs coûtant $10\times$ plus cher que les faux positifs), l'entropie croisée standard est une règle de score propre qui vise à estimer les probabilités a posteriori $P(y=1|x)$, mais la calibration doit être vérifiée et, si nécessaire, corrigée sur les données de validation. Déplacer le seuil de décision de classification basé sur la matrice de coûts métier $\tau = \frac{C_{FP}}{C_{FP} + C_{FN}}$ ou appliquer des poids d'échantillons est souvent plus propre et évite les dérivées personnalisées. Cependant, pour la régression asymétrique (par exemple, la perte pinball asymétrique pour la demande d'inventaire) ou les pénalités métier non linéaires où les objectifs standards ne peuvent pas guider la recherche de scissions, une fonction de perte personnalisée est justifiée.
2. **Exigences mathématiques pour le GBDT** : Dans les boosters du second ordre (XGBoost, LightGBM), une fonction de perte personnalisée $L(y, \hat{y})$ nécessite normalement des gradients de premier ordre calculables ($g_i = \partial L / \partial \hat{y}_i$) et des valeurs de courbure/Hessien de second ordre valides ($h_i = \partial^2 L / \partial \hat{y}_i^2$) pour le gain de scission et les calculs de poids de feuille ($w^* = -\sum g_i / (\sum h_i + \lambda)$). Les Hessiens doivent être non-négatifs ou approximés/tronqués en toute sécurité pour la stabilité numérique ; certaines implémentations supportent des objectifs de premier ordre ou approximatifs, donc l'exigence est spécifique au framework. Les mesures métier non différentiables ou discontinues doivent être remplacées par des approximations surrogates lisses (par exemple, variantes Huber ou log-cosh).
import numpy as np
import xgboost as xgb
def asymmetric_mse_objective(preds, dtrain):
labels = dtrain.get_label()
residual = preds - labels
# Penalize underestimation (residual < 0) 5x more heavily than overestimation
penalty = np.where(residual < 0, 5.0, 1.0)
grad = 2.0 * penalty * residual
hess = 2.0 * penalty
return grad, hess
# Usage:
# model = xgb.train(params, dtrain, obj=asymmetric_mse_objective)
15Qu'est-ce que LambdaMART, et comment adapte-t-il le boosting de gradient aux objectifs d'apprentissage de classement (Learning-to-Rank) ?
LambdaMART est un algorithme d'apprentissage de classement (Learning-to-Rank - LTR) qui combine MART (Multiple Additive Regression Trees / Boosting de Gradient) avec le framework LambdaRank. Dans le classement, les métriques cibles telles que le NDCG (Normalized Discounted Cumulative Gain - Gain Cumulatif Actualisé Normalisé) et le MAP (Mean Average Precision - Précision Moyenne) dépendent de l'ordre de tri discret (rangs), ce qui les rend presque partout plates et non-différentiables par rapport aux scores de modèle continus. LambdaMART contourne ce problème en construisant des gradients virtuels, appelés 'gradients lambda' ($\lambda_{ij}$), pour des paires d'éléments $(i, j)$ au sein de la même requête. Le gradient par paire de base provient d'une perte logistique sur les différences de scores ($s_i - s_j$). LambdaMART met à l'échelle ce gradient par le changement exact de la métrique de classement cible ($|\Delta \text{NDCG}_{ij}|$) qui se produirait si les positions du document $i$ et du document $j$ étaient échangées : $$\lambda_{ij} = \frac{-\sigma}{1 + e^{\sigma(s_i - s_j)}} |\Delta \text{NDCG}_{ij}|$$ Pour chaque document $i$ individuel, le gradient net est calculé en agrégeant les lambdas par paires pour toutes les paires impliquant le document $i$ : $\lambda_i = \sum_{j: j \succ i} \lambda_{ij} - \sum_{k: i \succ k} \lambda_{ki}$. Les arbres de régression standard dans l'ensemble de boosting ajustent ensuite ces gradients lambda composites par document à chaque itération de boosting, optimisant directement les métriques de classement par liste.
import lightgbm as lgb
import numpy as np
# Simulated query-grouped data: 2 queries with 3 docs each
X = np.random.randn(6, 10)
y = np.array([3, 1, 0, 2, 0, 1]) # Relevance grades (0-3)
group = [3, 3] # Query group sizes
train_data = lgb.Dataset(X, label=y, group=group)
params = {
'objective': 'lambdarank',
'metric': 'ndcg',
'ndcg_eval_at': [1, 3],
'learning_rate': 0.1,
'n_estimators': 50
}
ranker = lgb.train(params, train_data)