Skip to content

Du linéaire au polynomial et au multivarié

Le moteur construit dans les leçons précédentes (model, cost_function, grad, gradient_descent) ne sait rien de la « régression linéaire » en tant que telle : il ne fait qu’optimiser des paramètres theta pour une matrice X donnée. Changer la nature du problème revient simplement à changer la construction de X.

Avant de comparer plusieurs variantes, il faut une métrique d’évaluation en régression : le coefficient de détermination R² (déjà présenté au module 1), qui indique la part de variance expliquée par le modèle.

def r_squared(y, y_pred):
ss_res = np.sum((y - y_pred) ** 2)
ss_tot = np.sum((y - y.mean()) ** 2)
return 1 - ss_res / ss_tot

Au-delà d’un certain seuil de charge CPU, un phénomène de throttling thermique dégrade l’efficacité énergétique : la relation cesse d’être parfaitement linéaire.

consommation_nl = 8 * charge_cpu + 0.05 * charge_cpu ** 2 + 120 + bruit
charge_cpu_sq_std = standardize(charge_cpu ** 2)
X_poly = make_design_matrix(charge_cpu_std, charge_cpu_sq_std)
y_nl = consommation_nl.reshape(-1, 1)
theta_poly, cost_history_poly = gradient_descent(
X_poly, y_nl, np.random.randn(3, 1), learning_rate=0.05, n_iterations=3000
)
pred_poly = model(X_poly, theta_poly)

Aucune nouvelle fonction n’a été écrite : ajouter une colonne charge_cpu² à la matrice de design suffit à transformer une régression linéaire en régression polynomiale. C’est le modèle qui reste linéaire — linéaire en ses paramètres, pas nécessairement en la feature d’origine.

Un modèle linéaire sous-performe sur des données non linéaires

Section titled “Un modèle linéaire sous-performe sur des données non linéaires”
theta_lin_on_nl, _ = gradient_descent(
X_simple, y_nl, np.random.randn(2, 1), learning_rate=0.05, n_iterations=2000
)
pred_lin_on_nl = model(X_simple, theta_lin_on_nl)
print("R2 polynomial:", r_squared(y_nl, pred_poly))
print("R2 lineaire (sous-ajuste):", r_squared(y_nl, pred_lin_on_nl))
R2 polynomial: 0.9983942784910511
R2 lineaire (sous-ajuste): 0.990557913374649

L’écart est modeste ici (le terme quadratique reste discret sur la plage de charge observée), mais il est réel et mesurable : le modèle polynomial capture un peu mieux la courbure que le modèle purement linéaire, qui la lisse — un exemple concret de sous-apprentissage tel que défini au module 1.

Le même principe s’applique pour ajouter des variables plutôt que des puissances d’une même variable :

ram_pct = np.random.uniform(20, 90, n_samples)
trafic_reseau = np.random.uniform(5, 500, n_samples)
consommation_multi = 6 * charge_cpu + 3 * ram_pct + 0.2 * trafic_reseau + 80 + np.random.normal(0, 20, n_samples)
X_multi = make_design_matrix(standardize(charge_cpu), standardize(ram_pct), standardize(trafic_reseau))
y_multi = consommation_multi.reshape(-1, 1)
theta_multi, _ = gradient_descent(
X_multi, y_multi, np.random.randn(4, 1), learning_rate=0.05, n_iterations=5000
)
pred_multi = model(X_multi, theta_multi)
print("theta appris [cpu, ram, reseau, biais]:", theta_multi.ravel())
print("R2:", r_squared(y_multi, pred_multi))
theta appris [cpu, ram, reseau, biais]: [149.15378882 62.87138007 31.77429367 600.26004814]
R2: 0.9855857992044985

Trois variables standardisées, une colonne de biais, et c’est exactement le même gradient_descent qui s’applique — sans aucune modification. C’est la généralité de la formulation matricielle : model, cost_function et grad ne connaissent que la forme de X, jamais son contenu métier.

Le moteur sait désormais prédire une quantité continue. Passons à la prédiction d’une catégorie.

👉 Basculer vers la classification


Junior TSAFACK – 12/09/2026