SVR (Support Vector Regression) : Guide Complet — Principes, Exemples et Implémentation Python

SVR (Support Vector Regression) : Guide Complet — Principes, Exemples et Implémentation Python

SVR (Support Vector Regression) : Guide complet — Principes, Exemples et Implémentation Python

Le SVR (Support Vector Regression) transpose la philosophie des machines à vecteurs de support au domaine de la régression. Au lieu de chercher une marge maximale entre classes, le SVR cherche à contenir un maximum de points dans un tube d’épaisseur ε autour de la fonction de prédiction. Seules les erreurs hors de ce tube sont pénalisées.

Ce guide explore en détail le SVR : de la formulation mathématique du tube epsilon-insensible à l’implémentation pratique avec scikit-learn.


Principe mathématique

Concept du tube epsilon-insensible

Contrairement à la régression linéaire qui minimise la somme des erreurs quadratiques (MSE), la SVR régression introduit une zone d’insensibilité : toute prédiction située à moins de ε de la vraie valeur est considérée comme parfaite. Cela rend le modèle robuste aux petites fluctuations et au bruit.

La fonction de perte epsilon-insensible (Vapnik, 1995) est définie comme :

L_ε(y, f(x)) = max(0, |y - f(x)| - ε)

Autrement dit :
– Si l’erreur |y – f(x)| est inférieure à ε → perte = 0
– Si l’erreur dépasse ε → perte proportionnelle à l’excès

Formulation d’optimisation

Le problème primal du SVR est :

min ½||w||² + C Σ(ξᵢ + ξᵢ*)
sous contraintes :
  yᵢ - (w·φ(xᵢ) + b) ≤ ε + ξᵢ
  (w·φ(xᵢ) + b) - yᵢ ≤ ε + ξᵢ*
  ξᵢ, ξᵢ* ≥ 0

où :
– w est le vecteur de poids dans l’espace de features φ(x)
– C contrôle le compromis entre la régularisation (platness) et la pénalisation des erreurs
– ξᵢ et ξᵢ* sont les variables de slack pour les points au-dessus et en dessous du tube
– ε définit l’épaisseur du tube insensible

Formulation duale avec noyaux

Comme pour les SVM de classification, on résout le problème dual avec les multiplicateurs de Lagrange αᵢ et αᵢ* :

max -½ Σ(αᵢ-αᵢ*)(αⱼ-αⱼ*)K(xᵢ,xⱼ) - ε Σ(αᵢ+αᵢ*) + Σ yᵢ(αᵢ-αᵢ*)

sous contraintes : 0 ≤ αᵢ, αᵢ ≤ C et Σ(αᵢ-αᵢ) = 0.

La fonction de prédiction est :

f(x) = Σ(αᵢ-αᵢ*)K(xᵢ,x) + b

Seuls les points avec αᵢ ≠ 0 ou αᵢ ≠ 0 contribuent — ce sont les vecteurs de support* de la régression.

Noyaux disponibles

Le SVR supporte les mêmes noyaux que les SVM de classification :
Linéaire : K(x,x’) = x·x’ — pour les relations linéaires
Polynomial : K(x,x’) = (γ·x·x’ + r)^d — pour les courbes algébriques
RBF : K(x,x’) = exp(-γ||x-x’||²) — le plus polyvalent pour les relations non linéaires

Intuition — Comment comprendre le SVR ?

Imaginez que vous tracez une droite de régression. Dans la régression classique, chaque point qui s’écarte de la droite contribue à l’erreur. Avec le SVR régression, on crée un “tuyau” d’épaisseur ε autour de la droite. Tout ce qui est à l’intérieur du tuyau est gratuit — ça ne compte pas.

C’est comme si on disait au modèle : « je tolère des erreurs de taille ε, ne t’inquiète pas pour elles. Concentre-toi sur les vrais écarts. »

Cette idée a des conséquences puissantes :
Robustesse au bruit : le bruit de petite amplitude est absorbé par le tube
Sparsité : seuls les points hors du tube (vecteurs de support) influencent le modèle
Contrôle de la complexité : ε contrôle la “largeur” de la tolérance, C contrôle la sévérité de la pénalisation

Plus ε est grand, plus le modèle est simple (peu de points hors du tube, peu de vecteurs de support). Plus C est grand, plus le modèle pénalise les erreurs hors du tube.

Implémentation Python — Exemple complet

Exemple 1 : SVR linéaire vs RBF

import numpy as np
import matplotlib.pyplot as plt
from sklearn.svm import SVR, LinearSVR
from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.metrics import mean_squared_error, r2_score

# Données sinusoïdales bruitées
np.random.seed(42)
X = np.sort(5 * np.random.rand(200, 1), axis=0)
y = np.sin(X).ravel() + 0.1 * np.random.randn(200)

# Division train/test
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Standardisation
scaler_X = StandardScaler()
scaler_y = StandardScaler()
X_tr = scaler_X.fit_transform(X_train)
y_tr = scaler_y.fit_transform(y_train.reshape(-1, 1)).ravel()
X_te = scaler_X.transform(X_test)

# SVR avec noyau RBF
svr_rbf = SVR(kernel='rbf', C=10, gamma='scale', epsilon=0.1)
svr_rbf.fit(X_tr, y_tr)
y_pred_rbf = scaler_y.inverse_transform(svr_rbf.predict(X_te).reshape(-1, 1)).ravel()

# SVR linéaire
svr_lin = SVR(kernel='linear', C=1.0, epsilon=0.1)
svr_lin.fit(X_tr, y_tr)
y_pred_lin = scaler_y.inverse_transform(svr_lin.predict(X_te).reshape(-1, 1)).ravel()

# LinearSVR (alternative optimisée)
lsvr = LinearSVR(C=1.0, epsilon=0.1, max_iter=5000)
lsvr.fit(X_tr, y_tr)
y_pred_lsvr = scaler_y.inverse_transform(lsvr.predict(X_te).reshape(-1, 1)).ravel()

# Évaluation
for name, y_pred in [('SVR RBF', y_pred_rbf), ('SVR Linéaire', y_pred_lin),
                      ('LinearSVR', y_pred_lsvr)]:
    r2 = r2_score(y_test, y_pred)
    rmse = np.sqrt(mean_squared_error(y_test, y_pred))
    print(f'{name:15s} -> R2={r2:.4f}, RMSE={rmse:.4f}')

# Visualisation
X_plot = np.linspace(0, 5, 300).reshape(-1, 1)
X_plot_scaled = scaler_X.transform(X_plot)

plt.figure(figsize=(10, 6))
plt.scatter(X_train, y_train, c='darkblue', label='Données d entraînement', alpha=0.6, s=20)
plt.scatter(X_test, y_test, c='orange', label='Données de test', alpha=0.8, s=20)

for name, pred_func, style in [
    ('SVR RBF', lambda x: scaler_y.inverse_transform(svr_rbf.predict(scaler_X.transform(x)).reshape(-1,1)).ravel(), 'r-'),
    ('SVR Linéaire', lambda x: scaler_y.inverse_transform(svr_lin.predict(scaler_X.transform(x)).reshape(-1,1)).ravel(), 'g--'),
]:
    plt.plot(X_plot, pred_func(X_plot), style, linewidth=2, label=name)

plt.xlabel('X')
plt.ylabel('y')
plt.title('SVR RBF vs Linéaire sur données sinusoïdales')
plt.legend()
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Exemple 2 : Impact de epsilon et C

# Impact de epsilon
epsilons = [0.01, 0.05, 0.1, 0.2, 0.5, 1.0]
r2_scores = []
n_support = []

for eps in epsilons:
    svr = SVR(kernel='rbf', C=10, gamma='scale', epsilon=eps)
    svr.fit(X_tr, y_tr)
    pred = scaler_y.inverse_transform(svr.predict(X_te).reshape(-1, 1)).ravel()
    r2 = r2_score(y_test, pred)
    r2_scores.append(r2)
    n_support.append(len(svr.support_vectors_))
    print(f'Epsilon={eps:.2f} -> R2={r2:.4f}, nb vecteurs support={len(svr.support_vectors_)}')

plt.figure(figsize=(8, 5))
plt.plot(epsilons, r2_scores, 'bo-', linewidth=2)
plt.xlabel('Epsilon (largeur du tube insensible)', fontsize=12)
plt.ylabel('R2 Score (test)', fontsize=12)
plt.title('Impact d epsilon sur la performance du SVR')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

# Impact de C
Cs = [0.01, 0.1, 1, 10, 100]
r2_c = []
for c in Cs:
    svr = SVR(kernel='rbf', C=c, gamma='scale', epsilon=0.1)
    svr.fit(X_tr, y_tr)
    pred = scaler_y.inverse_transform(svr.predict(X_te).reshape(-1, 1)).ravel()
    r2 = r2_score(y_test, pred)
    r2_c.append(r2)
    print(f'C={c:.2f} -> R2={r2:.4f}')

plt.figure(figsize=(8, 5))
plt.semilogx(Cs, r2_c, 'ro-', linewidth=2)
plt.xlabel('C (pénalisation des erreurs)', fontsize=12)
plt.ylabel('R2 Score (test)', fontsize=12)
plt.title('Impact de C sur la performance du SVR')
plt.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()

Exemple 3 : Grid Search et comparaison

from sklearn.model_selection import GridSearchCV

param_grid = {
    'kernel': ['rbf', 'linear'],
    'C': [0.1, 1, 10, 100],
    'epsilon': [0.01, 0.1, 0.5],
    'gamma': ['scale', 'auto', 0.01, 0.1, 1]
}

grid = GridSearchCV(SVR(), param_grid, cv=5, scoring='neg_mean_squared_error', n_jobs=-1)
grid.fit(X_tr, y_tr)

print(f'Meilleurs hyperparametres: {grid.best_params_}')
print(f'Meilleur MSE (CV): {-grid.best_score_:.4f}')

# Predictions avec le meilleur modèle
best_svr = grid.best_estimator_
y_pred_best = scaler_y.inverse_transform(best_svr.predict(X_te).reshape(-1, 1)).ravel()
r2 = r2_score(y_test, y_pred_best)
print(f'R2 sur test: {r2:.4f}')

Hyperparamètres

Hyperparamètre Rôle Valeurs typiques Impact
C Régularisation (inverse) 0.01, 0.1, 1, 10, 100 Petit C = modèle plus lisse, tolère les erreurs. Grand C = pénalise fortement les erreurs hors du tube.
epsilon Largeur du tube insensible 0.01, 0.1 (défaut), 0.5 Plus ε est grand, plus le tube est large et moins il y a de vecteurs de support. Contrôle la parsimonie du modèle.
kernel Type de noyau ‘rbf’ (défaut), ‘linear’, ‘poly’ RBF pour les relations non linéaires, linéaire pour les relations simples haute dimension.
gamma Échelle du noyau RBF ‘scale’ (défaut), ‘auto’, 0.01-10 Gamma élevé = frontières complexes. Gamma faible = modèle plus lisse.
degree Degré du polynôme 2, 3 Utilisé uniquement avec kernel=’poly’
max_iter Limite d’itérations -1 (illimité), 1000 Augmenter si non-convergence.

Avantages et Limites

Avantages

  • Robustesse au bruit : le tube epsilon absorbe les petites fluctuations
  • Sparsité : seuls les points hors du tube comptent, modèle compact
  • Non-linéarité contrôlée : mêmes noyaux que les SVM (RBF, polynomial)
  • Pas d’hypothèse de distribution : contrairement à la régression linéaire qui suppose une erreur gaussienne
  • Généralisation : bonne performance sur des données non vues, même en petite dimension

Limites

  • Sensible à la standardisation : obligatoire, comme tous les SVM
  • Coûteux en calcul : O(n²) pour l’entraînement, O(n_sv) pour la prédiction
  • Réglage délicat : 3-4 hyperparamètres à ajuster simultanément (C, ε, γ)
  • Interprétabilité faible : difficile d’expliquer pourquoi une prédiction prend une certaine valeur
  • Peu performant sur très gros datasets : au-delà de 100 000 points, privilégier les gradient boosting

Cas d’usage

1. Prédiction de séries temporelles

Le SVR avec noyau RBF excelle pour modéliser des tendances non linéaires dans les séries temporelles (prix, température, demande). Le tube epsilon absorbe le bruit de mesure tout en capturant les tendances.

Estimation de prix immobiliers

Les relations entre surface, localisation, nombre de pièces et prix sont rarement linéaires. Le SVR RBF modélise ces interactions complexes sans hypothèse de forme fonctionnelle.

Calibration de capteurs industriels

En industrie, la relation entre la lecture brute d’un capteur et la valeur physique réelle est souvent non linéaire. Le SVR peut être utilisé pour calibrer les capteurs avec une précision supérieure à la régression polynomiale.

Prédiction de qualité en production

Dans l’industrie pharmaceutique ou agroalimentaire, prédire la qualité d’un lot à partir de paramètres de production. Le tube epsilon permet de définir des zones de tolérance naturellement.

Bonnes pratiques

  1. Standardisez systématiquement les features (StandardScaler) et les cibles si leur amplitude est grande.
  2. Commencez par epsilon=0.1 et ajustez selon l’échelle de votre variable cible.
  3. Grid Search sur C et epsilon : ces deux paramètres sont les plus influents.
  4. Comparez SVR RBF et linéaire : le linéaire peut suffire en haute dimension.
  5. Surveillez le nombre de vecteurs de support : s’il approche n, votre modèle est probablement en surapprentissage.

Voir aussi


Comparaison SVR vs autres methodes de regression

La SVR regression n’est pas l’unique option pour les relations non lineaires. Comparons-la avec les alternatives les plus courantes :

SVR vs Regression Lineaire : la regression lineaire suppose une relation lineaire et minimise le MSE global. La SVR est plus flexible grace aux noyaux, et son tube epsilon la rend plus robuste aux outliers.

SVR vs Random Forest : le random forest est plus facile a regler (moins d’hyperparametres sensibles) et gere naturellement les features non standardisees. Mais la SVR offre une meilleure generalisation sur les petits datasets (< 10000 points).

SVR vs Gradient Boosting : le gradient boosting (XGBoost, LightGBM) est souvent superieur en precision pure sur les tableaux de donnees. La SVR garde l’avantage quand on a peu de donnees et besoin de robustesse theorique.

SVR vs Reseaux de neurones : les reseaux de neurones surpassent la SVR sur les gros volumes de donnees et les problemes tres complexes. Mais la SVR est plus simple a entrainer, avec des garanties theoriques de convergence globale.

En resume : la SVR excelle sur les datasets de taille petite a moyenne (100 a 10000 points) avec des relations non lineaires, quand on veut un modele robuste avec des garanties theoriques.

Exemple 4 : SVR avec LinearSVR pour les gros datasets

Quand on travaille avec plus de 10000 echantillons, SVR avec noyau RBF devient lent. LinearSVR utilise l’algorithme liblinear, bien plus rapide :

from sklearn.svm import LinearSVR
from sklearn.datasets import make_regression

X, y = make_regression(n_samples=50000, n_features=20, noise=0.1, random_state=42)

lsvr = LinearSVR(C=1.0, epsilon=0.1, max_iter=2000, dual='auto')
lsvr.fit(X, y)
print(f'Coefficients: {lsvr.coef_[:5]}')  # Les 5 premiers
print(f'Intercept: {lsvr.intercept_:.4f}')
print(f'R2: {lsvr.score(X, y):.4f}')

LinearSVR ne supporte que le noyau lineaire, mais c’est un excellent point de depart pour les gros volumes.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur la façon dont les données de vos commentaires sont traitées.