Support Vector Machine en R : SVM linéaire, polynomial et radial
Trouvez la frontière à marge maximale, ajustez le coût et le noyau, et évaluez honnêtement un SVM tidymodels
Un guide pratique du support vector machine (SVM) pour la classification en R. Construisez des classifieurs SVM linéaires, polynomiaux et radiaux (RBF), comprenez comment fonctionnent la frontière à marge maximale et ses vecteurs de support, ajustez le coût C (souplesse de la marge) et le sigma RBF par validation croisée, et découvrez pourquoi vous devez d’abord standardiser les prédicteurs. Travaillé à la manière moderne tidymodels avec parsnip + kernlab dans un workflow, avec une note sur kernlab::ksvm et e1071::svm. Évalué sur l’exactitude et l’AUC ROC, sur les données PimaIndiansDiabetes2.
Date de publication
25 juin 2026
Modifié
7 juillet 2026
AstuceL’essentiel à retenir
Un support vector machine (SVM) classe en trouvant la frontière à la marge la plus large — la frontière séparatrice qui se tient le plus loin possible des points les plus proches de chaque classe. Seuls ces points les plus proches, les vecteurs de support, définissent la frontière ; tout le reste est sans importance.
Les données réelles sont rarement linéairement séparables, donc le SVM utilise l’astuce du noyau pour courber la frontière : un noyau linéaire trace une frontière droite, tandis que les noyaux polynomial et radial (RBF) tracent des frontières courbes et non linéaires.
Le coût C contrôle la souplesse de la marge : un petit C autorise davantage de violations de marge (une frontière plus large et plus indulgente qui généralise), un grand C punit chaque erreur (une frontière plus serrée qui peut surapprendre). Le noyau RBF ajoute un second réglage, rbf_sigma, qui détermine à quel point la frontière est sinueuse.
Standardisez d’abord les prédicteurs — le SVM mesure des distances, donc un prédicteur exprimé dans de grandes unités dominerait la marge. Utilisez toujours step_normalize() (ou la mise à l’échelle intégrée de kernlab).
Vous ajustez C (et sigma) par validation croisée, jamais à l’aveugle. La manière moderne : parsnip::svm_linear()/svm_poly()/svm_rbf() sur le moteur "kernlab" à l’intérieur d’un workflow, ajustés avec tune_grid() ; la manière classique : kernlab::ksvm() ou e1071::svm() directement.
Sur les données de diabète Pima, les noyaux linéaire et polynomial atteignent environ 76 % d’exactitude en test / 0.84 d’AUC ROC, tandis que le noyau radial est ici un peu moins bon (~72 % / 0.80) — donc le simple SVM linéaire égale ou dépasse les plus sophistiqués. Ajustez et comparez toujours plutôt que de supposer qu’un noyau courbe l’emporte.
Vous disposez d’un jeu de données clinique et d’une question oui/non : un patient sera-t-il positif au diabète, à partir d’une poignée de mesures — glucose, IMC, âge, pression artérielle, et ainsi de suite ? Vous voulez un classifieur qui trace une ligne (ou une courbe) nette entre les patients diabète-positif et diabète-négatif, et vous voulez que cette frontière généralise à des patients qu’il n’a jamais vus.
Le support vector machine (SVM) est conçu exactement pour cela. Son idée est géométrique et intuitive : parmi toutes les frontières qui séparent les deux classes, choisir celle à la marge la plus large — la frontière qui conserve le plus grand écart possible de chaque côté. Une marge large est une frontière confiante et robuste, et elle ne dépend que de la poignée de points situés juste au bord de cet écart. Ces points frontaliers sont les vecteurs de support, et ils donnent son nom à la méthode.
La plupart des frontières réelles ne sont pas droites, donc le SVM dispose d’une seconde astuce. À travers le noyau, il peut courber la frontière en une courbe — une frontière polynomiale ou, le plus souvent, radiale (RBF) — sans jamais quitter le confort de la même optimisation. Cette leçon construit des classifieurs SVM des trois manières, ajuste honnêtement leurs paramètres de coût et de noyau par validation croisée, et les évalue sur un jeu de test mis de côté avec l’exactitude et l’AUC ROC.
Nous travaillons à la manière moderne tidymodels — les spécifications svm_*() de parsnip sur le moteur kernlab à l’intérieur d’un workflow — et notons aussi les routes classiques kernlab::ksvm() / e1071::svm(). Le SVM est un classifieur d’une famille : pour les alternatives de type régression ou interprétables voyez la régression logistique pénalisée, et pour lire la matrice de confusion et la courbe ROC en profondeur voyez l’évaluation des modèles de classification.
NoteQuand y recourir
Utilisez un SVM lorsque vous voulez un solide classifieur binaire (ou multi-classe) et que vous soupçonnez que la frontière entre les classes peut être non linéaire. Le SVM brille sur les jeux de données de taille moyenne avec de nombreux prédicteurs, gère bien une frontière non linéaire grâce au noyau, et est robuste parce qu’il s’appuie uniquement sur les vecteurs de support. Tournez-vous ailleurs lorsque vous avez besoin de probabilités calibrées ou de coefficients interprétables d’emblée — le SVM donne une frontière de décision, pas des odds ratio.
Les données
Nous utilisons le jeu de données PimaIndiansDiabetes2 du package mlbench : 768 femmes d’origine amérindienne Pima, avec pour objectif de prédire le diabetes (un résultat binaire pos/neg) à partir de huit prédicteurs cliniques — le nombre de grossesses (pregnant), le glucose plasmatique, la pressure sanguine, l’épaisseur du pli cutané du triceps, l’insulin sérique, l’indice de masse corporelle (mass, IMC), la fonction pedigree du diabète, et l’age.
Cette version enregistre les valeurs manquantes en NA lorsqu’une mesure est invraisemblable (p. ex. un glucose à zéro). Le SVM a besoin de cas complets, donc — en suivant l’analyse source — nous supprimons les lignes avec des NA, laissant 392 enregistrements complets. Nous découpons ensuite en un jeu d’entraînement (80 %, pour l’ajustement et le réglage) et un jeu de test (20 %, mis de côté pour juger honnêtement le classifieur final), stratifié sur diabetes afin que les deux jeux conservent le même équilibre positif/négatif, avec une graine pour la reproductibilité :
library(rsample)data("PimaIndiansDiabetes2", package ="mlbench")# Drop rows with missing measurements (SVM needs complete cases)pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)c(complete =nrow(pima), train =nrow(train_data), test =nrow(test_data))
complete train test
392 313 79
# The stratified split preserves the class balanceprop.table(table(train_data$diabetes))
Environ 313 patients pour apprendre, 79 mis de côté pour faire office de juge, et 8 prédicteurs. Environ un tiers des patients sont diabète-positif — un problème de classification modérément déséquilibré mais exploitable.
Ce que fait réellement un SVM : la marge et les vecteurs de support
Avant tout réglage, il est utile de voir ce que dessine un SVM. Ci-dessous, nous ajustons un SVM à noyau radial sur seulement deux prédicteurs — glucose et mass (IMC) — afin de pouvoir tracer sa frontière de décision sur le plan. Nous standardisons d’abord les deux (le SVM mesure des distances ; les prédicteurs doivent partager une échelle), puis colorons toute la région selon la prédiction du modèle et superposons les patients colorés selon leur classe réelle :
library(kernlab)library(ggplot2)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)# Two predictors so the boundary is drawable; standardize themd <- pima[, c("glucose", "mass", "diabetes")]d$glucose <-as.numeric(scale(d$glucose))d$mass <-as.numeric(scale(d$mass))# A radial-kernel SVM on the two predictorsset.seed(123)fit2d <-ksvm(diabetes ~ glucose + mass, data = d,kernel ="rbfdot", C =1, kpar ="automatic")# Predict over a fine grid to paint the decision regionsgx <-seq(min(d$glucose), max(d$glucose), length =200)gy <-seq(min(d$mass), max(d$mass), length =200)grid <-expand.grid(glucose = gx, mass = gy)grid$pred <-predict(fit2d, grid)ggplot() +geom_tile(data = grid, aes(glucose, mass, fill = pred), alpha =0.25) +geom_point(data = d, aes(glucose, mass, color = diabetes), size =1.3, alpha =0.8) +scale_fill_manual(values =c(neg ="#3a86d4", pos ="#e15759"),name ="Predicted") +scale_color_manual(values =c(neg ="#3a86d4", pos ="#e15759"),name ="Actual") +labs(x ="Glucose (standardized)", y ="BMI (standardized)",title ="A radial SVM decision boundary (Pima diabetes)",subtitle ="The frontier is curved — that is the kernel at work") +theme_minimal()
Lisez l’image. Le plan est divisé en une région bleue diabète-négatif (surtout faible glucose) et une région rouge diabète-positif (surtout fort glucose), et la frontière entre elles est courbe, non droite — cette courbure est le noyau radial à l’œuvre. Les patients (les points) atterrissent majoritairement dans la bonne région, avec le mélange attendu près de la frontière où la décision est véritablement difficile. Quelques « îlots » apparaissent là où des regroupements locaux d’une classe poussent la frontière autour d’eux.
La frontière n’a besoin que des points proches d’elle — les vecteurs de support. Les points profondément à l’intérieur de leur propre région pourraient être supprimés sans déplacer la ligne du tout ; seuls les cas frontaliers comptent. C’est toute l’économie d’un SVM : une frontière définie par un petit ensemble décisif de points, avec la marge la plus large possible autour d’elle.
NoteLinéaire ou non linéaire, en une phrase
Remplacez kernel = "rbfdot" par kernel = "vanilladot" ci-dessus et la frontière devient une ligne droite — un SVM linéaire. Les noyaux polynomial ("polydot") et radial ("rbfdot") permettent au même algorithme de tracer des frontières courbes en projetant implicitement les données dans un espace de plus grande dimension (l’astuce du noyau), où une coupe droite redevient une courbe dans les prédicteurs d’origine.
Le SVM linéaire : ajuster le coût par validation croisée
Passons maintenant au vrai modèle sur les huit prédicteurs. En tidymodels, un SVM n’est qu’une spécification parsnip différente sur le moteur kernlab ; tout le reste est l’enchaînement découpage → recipe → réglage → finalisation du workflow tidymodels. La recipe normalise les prédicteurs (le SVM mesure des distances, donc une échelle commune est obligatoire), et nous laissons le coût C à ajuster.
C est le réglage clé du SVM. Il contrôle avec quelle sévérité le modèle punit une violation de marge — un point du mauvais côté de la marge, ou à l’intérieur de celle-ci :
Petit C → une marge souple et large. Le modèle tolère quelques points d’entraînement mal classés en échange d’une frontière plus simple qui généralise habituellement mieux.
Grand C → une marge dure et étroite. Le modèle s’efforce de classer correctement chaque point d’entraînement, ce qui peut surapprendre le bruit de l’entraînement.
Nous évaluons chaque C candidat par validation croisée à 10 plis sur le jeu d’entraînement, sur l’exactitude et l’AUC ROC, puis conservons le meilleur :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)# Standardize the predictors — SVM measures distances, so scale mattersrec <-recipe(diabetes ~ ., data = train_data) |>step_normalize(all_numeric_predictors())# Linear SVM, cost left to be tunedsvm_lin_spec <-svm_linear(cost =tune()) |>set_engine("kernlab") |>set_mode("classification")svm_lin_wf <-workflow() |>add_recipe(rec) |>add_model(svm_lin_spec)# 10-fold CV over a grid of cost valuesset.seed(123)folds <-vfold_cv(train_data, v =10, strata = diabetes)cost_grid <-grid_regular(cost(range =c(-3, 3)), levels =15) # C from 2^-3 to 2^3set.seed(123)svm_lin_tuned <-tune_grid( svm_lin_wf, resamples = folds, grid = cost_grid,metrics =metric_set(accuracy, roc_auc))# The cost with the best cross-validated accuracybest_cost <-select_best(svm_lin_tuned, metric ="accuracy")best_cost
tune_grid() a validé par validation croisée chaque coût candidat ; select_best() renvoie le gagnant. Ici le C choisi est petit (environ 0.125) — la marge souple et indulgente généralise le mieux sur ces données. C’est un résultat courant : sur des données réelles bruitées, une marge plus large l’emporte sur une marge plus serrée.
La courbe de réglage : exactitude vs coût
Le diagnostic le plus utile lors du réglage d’un SVM est l’exactitude validée par validation croisée en fonction du coût. Il montre tout le compromis biais–variance en une seule image :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)library(ggplot2)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)rec <-recipe(diabetes ~ ., data = train_data) |>step_normalize(all_numeric_predictors())svm_lin_spec <-svm_linear(cost =tune()) |>set_engine("kernlab") |>set_mode("classification")svm_lin_wf <-workflow() |>add_recipe(rec) |>add_model(svm_lin_spec)set.seed(123); folds <-vfold_cv(train_data, v =10, strata = diabetes)cost_grid <-grid_regular(cost(range =c(-3, 3)), levels =15)set.seed(123)svm_lin_tuned <-tune_grid(svm_lin_wf, resamples = folds, grid = cost_grid,metrics =metric_set(accuracy, roc_auc))best_cost <-select_best(svm_lin_tuned, metric ="accuracy")# Collect the CV accuracy for every candidate costacc_curve <-subset(collect_metrics(svm_lin_tuned), .metric =="accuracy")ggplot(acc_curve, aes(x = cost, y = mean)) +geom_line(color ="#3a86d4", linewidth =1) +geom_point(color ="#3a86d4", size =1.8) +geom_vline(xintercept = best_cost$cost, linetype ="dashed", color ="gray40") +scale_x_log10() +labs(x ="Cost C (log scale)", y ="Cross-validated accuracy",title ="Choosing the SVM cost by cross-validation",subtitle ="Accuracy peaks at a small, soft-margin cost (dashed = best C)" ) +theme_minimal()
Lisez-la de gauche à droite. Pour un petit coût (à gauche), la marge est souple et large, et l’exactitude validée par validation croisée est à son meilleur. À mesure que le coût augmente (à droite), la marge se resserre, le modèle se met à courir après des points d’entraînement individuels, et l’exactitude dérive vers le bas et s’aplatit. La ligne pointillée marque le gagnant de la validation croisée — le point d’équilibre entre une marge trop souple (sous-apprentissage) et une marge trop dure (surapprentissage).
Finaliser et évaluer sur le jeu de test
Nous finalisons le workflow avec le coût choisi et last_fit() — ajustement sur toutes les données d’entraînement et évaluation une seule fois sur le jeu de test intact :
library(rsample)library(recipes)library(parsnip)library(workflows)library(tune)library(dials)library(yardstick)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)rec <-recipe(diabetes ~ ., data = train_data) |>step_normalize(all_numeric_predictors())svm_lin_spec <-svm_linear(cost =tune()) |>set_engine("kernlab") |>set_mode("classification")svm_lin_wf <-workflow() |>add_recipe(rec) |>add_model(svm_lin_spec)set.seed(123); folds <-vfold_cv(train_data, v =10, strata = diabetes)cost_grid <-grid_regular(cost(range =c(-3, 3)), levels =15)set.seed(123)svm_lin_tuned <-tune_grid(svm_lin_wf, resamples = folds, grid = cost_grid,metrics =metric_set(accuracy, roc_auc))best_cost <-select_best(svm_lin_tuned, metric ="accuracy")# Finalize with the chosen cost, fit on train, score ONCE on testfinal_lin <-finalize_workflow(svm_lin_wf, best_cost) |>last_fit(split)collect_metrics(final_lin)
Lisez les chiffres — la performance honnête, hors échantillon, de votre SVM linéaire :
Exactitude ≈ 0.76 — le modèle juge correctement le diabète environ 76 % du temps sur des patients qu’il n’a jamais vus pendant l’ajustement. Utile, mais à lire à côté de l’AUC, car l’exactitude peut flatter un modèle sur un résultat déséquilibré.
AUC ROC ≈ 0.85 — la probabilité que le modèle attribue à un positif aléatoire un score plus élevé qu’à un négatif aléatoire. 0.5 est un tirage à pile ou face, 1.0 est parfait ; 0.85 est un classifieur réellement bon. Parce que l’AUC est indépendante du seuil, elle juge le classement du modèle, et non un seuil arbitraire de 0.5. (Un score brier_class apparaît aussi — une mesure « plus c’est bas, mieux c’est » de la qualité des probabilités ; voyez l’évaluation des modèles de classification.)
SVM non linéaire : les noyaux radial et polynomial
Le SVM linéaire trace une frontière droite. Quand la vraie frontière est courbe, un noyau non linéaire fait mieux. Les deux chevaux de trait :
Radial / RBF (svm_rbf()) — le choix par défaut ; une frontière courbe lisse et flexible. Il ajoute un second réglage, rbf_sigma, qui détermine à quel point la frontière est sinueuse : un grand sigma fait une frontière serrée et locale (risque de surapprentissage), un petit sigma une frontière lisse et globale.
Polynomial (svm_poly()) — une frontière en forme de courbe polynomiale, avec le degree contrôlant sa flexibilité (le degré 1 est linéaire, le 2 quadratique, et ainsi de suite).
Le workflow est identique — seule la spécification change. Nous ajustons les paramètres du noyau par validation croisée avec une grille remplissant l’espace, puis évaluons chaque modèle finalisé sur le jeu de test :
maximum number of iterations reached 0.007125988 0.007066688maximum number of iterations reached 0.000277231 0.0002772305maximum number of iterations reached 1.818525e-05 1.818525e-05maximum number of iterations reached 0.005606554 0.005509965maximum number of iterations reached 0.001894696 0.001894422maximum number of iterations reached 0.0001352326 0.0001352321maximum number of iterations reached 0.007771957 0.007697452maximum number of iterations reached 0.0002981254 0.0002981237maximum number of iterations reached 1.950506e-05 1.950506e-05maximum number of iterations reached 0.004951154 0.004863774maximum number of iterations reached 0.00204731 0.002046965maximum number of iterations reached 0.0001569284 0.0001569279maximum number of iterations reached 0.007417196 0.007357442maximum number of iterations reached 0.0002906193 0.0002906176maximum number of iterations reached 1.842763e-05 1.842762e-05maximum number of iterations reached 0.005711461 0.005584952maximum number of iterations reached 0.001945907 0.001945621maximum number of iterations reached 0.000143465 0.0001434646maximum number of iterations reached 0.008260928 0.008163126maximum number of iterations reached 0.0003420105 0.0003420079maximum number of iterations reached 2.401839e-05 2.401838e-05maximum number of iterations reached 0.005412609 0.005299179maximum number of iterations reached 0.002321359 0.002320826maximum number of iterations reached 0.000178926 0.0001789252maximum number of iterations reached 0.007543963 0.00747871maximum number of iterations reached 0.0003148769 0.0003148757maximum number of iterations reached 2.141298e-05 2.141298e-05maximum number of iterations reached 0.004977226 0.004881916maximum number of iterations reached 0.002026426 0.002026071maximum number of iterations reached 0.0001486634 0.0001486628maximum number of iterations reached 0.007999958 0.007923292maximum number of iterations reached 0.0003135545 0.0003135524maximum number of iterations reached 1.928426e-05 1.928425e-05maximum number of iterations reached 0.004539986 0.004485015maximum number of iterations reached 0.002026131 0.002025765maximum number of iterations reached 0.000154286 0.0001542855maximum number of iterations reached 0.007360605 0.007298256maximum number of iterations reached 0.0002908 0.0002907982maximum number of iterations reached 1.941965e-05 1.941965e-05maximum number of iterations reached 0.005145438 0.005042113maximum number of iterations reached 0.001950196 0.001949894maximum number of iterations reached 0.0001437948 0.0001437943maximum number of iterations reached 0.007565563 0.007499821maximum number of iterations reached 0.0003203407 0.0003203397maximum number of iterations reached 2.048476e-05 2.048476e-05maximum number of iterations reached 0.004989485 0.004906222maximum number of iterations reached 0.002111761 0.002111319maximum number of iterations reached 0.0001560655 0.0001560648maximum number of iterations reached 0.008008199 0.007927276maximum number of iterations reached 0.000340234 0.0003402325maximum number of iterations reached 2.152958e-05 2.152957e-05maximum number of iterations reached 0.005209444 0.005115809maximum number of iterations reached 0.002184366 0.002183934maximum number of iterations reached 0.0001696517 0.0001696511maximum number of iterations reached 0.007046988 0.006989501maximum number of iterations reached 0.0002873389 0.0002873379maximum number of iterations reached 1.864396e-05 1.864396e-05maximum number of iterations reached 0.005475701 0.005346058maximum number of iterations reached 0.001891311 0.001891039maximum number of iterations reached 0.0001391842 0.0001391836
Sur les données Pima, le noyau polynomial atteint essentiellement la même exactitude et la même AUC que le SVM linéaire (~0.76 / ~0.84), tandis que le noyau radial est ici un peu moins bon (~0.72 / ~0.80). C’est en soi un résultat utile : la frontière du diabète est ici assez proche du linéaire pour que la flexibilité supplémentaire d’un noyau courbe n’apporte rien — et la frontière plus sinueuse du noyau radial coûte en fait un peu. Sur ces données, le noyau linéaire (et polynomial) égale ou dépasse le radial, donc le simple SVM linéaire est le choix par défaut sensé — il est plus rapide à ajuster, a un paramètre de moins à régler, et est moins sujet au surapprentissage. Ajustez et comparez toujours sur le même jeu de test plutôt que de supposer qu’un noyau plus sophistiqué l’emporte ; les noyaux courbes gagnent leur place sur des données à frontière véritablement non linéaire, ce qui est courant mais pas universel.
NoteQuel noyau dois-je utiliser ?
Linéaire (svm_linear) — le premier essai par défaut, surtout avec de nombreux prédicteurs. Rapide, robuste, un paramètre (cost). S’il s’en sort bien, arrêtez-vous ici.
Radial / RBF (svm_rbf) — le noyau non linéaire de référence. Flexible et lisse ; ajustez costetrbf_sigma. Le choix standard quand le SVM linéaire sous-apprend.
Polynomial (svm_poly) — une frontière courbe d’un degree choisi ; utile lorsque vous attendez une structure polynomiale spécifique, sinon le RBF est habituellement plus facile à régler. Ajustez toujours par validation croisée et comparez sur le même jeu de test mis de côté, comme ci-dessus.
La route classique : kernlab::ksvm et e1071::svm
La plupart des utilisateurs de R rencontrent d’abord le SVM via kernlab::ksvm() ou e1071::svm() directement — utile à connaître, car beaucoup de code existant (et la route originelle method = "svmLinear"/"svmRadial" de caret) repose sur eux. Standardisez vous-même les prédicteurs (ou utilisez la mise à l’échelle intégrée du moteur) et appelez la fonction :
library(kernlab)library(rsample)data("PimaIndiansDiabetes2", package ="mlbench")pima <-na.omit(PimaIndiansDiabetes2)set.seed(123)split <-initial_split(pima, prop =0.80, strata = diabetes)train_data <-training(split)test_data <-testing(split)# ksvm scales the predictors by default (scaled = TRUE); radial kernel, cost C = 1set.seed(123)fit_ksvm <-ksvm(diabetes ~ ., data = train_data,kernel ="rbfdot", C =1, kpar ="automatic")fit_ksvm
Support Vector Machine object of class "ksvm"
SV type: C-svc (classification)
parameter : cost C = 1
Gaussian Radial Basis kernel function.
Hyperparameter : sigma = 0.128432254141048
Number of Support Vectors : 178
Objective Function Value : -128.2245
Training error : 0.153355
# Accuracy on the held-out test setpred <-predict(fit_ksvm, test_data)mean(pred == test_data$diabetes)
[1] 0.7088608
ksvm() affiche le noyau, le coût, le rbf_sigma ajusté qu’il a choisi automatiquement, et le nombre de vecteurs de support — les points qui définissent réellement la frontière. L’exactitude en test est dans le même ordre de grandeur que les modèles tidymodels ajustés. Le package e1071 propose la même chose avec un vocabulaire légèrement différent : svm(diabetes ~ ., data = train_data, kernel = "radial", cost = 1, scale = TRUE), avec tune.svm() pour une recherche sur grille sur cost et gamma. Les deux conviennent ; tidymodels vous donne simplement un harnais de réglage + d’évaluation cohérent pour chaque modèle de ce pilier.
NoteLa marge et l’astuce du noyau (optionnel)
Un SVM linéaire cherche un hyperplan séparateur \(w^\top x + b = 0\) et choisit celui à la marge la plus large — le plus grand écart \(2 / \lVert w \rVert\) entre les deux classes. Avec une marge souple, il résout
\[
\min_{w,\,b,\,\xi} \;\; \tfrac{1}{2}\lVert w \rVert^2 \; + \; C \sum_i \xi_i ,
\]
sous la contrainte que chaque point soit du bon côté à un relâchement \(\xi_i \ge 0\) près. Le premier terme élargit la marge ; le second pénalise les violations, le coût \(C\) réglant le compromis — un grand \(C\) signifie peu de violations (une marge dure et étroite), un petit \(C\) une marge plus souple et plus large. La solution ne dépend que des points avec \(\xi_i > 0\) ou situés sur le bord de la marge : les vecteurs de support.
La partie astucieuse est que l’optimisation n’utilise les données qu’à travers des produits scalaires\(x_i^\top x_j\) entre points. Remplacez ce produit scalaire par un noyau\(K(x_i, x_j)\) et vous projetez implicitement les données dans un espace de plus grande dimension où un séparateur droit existe — sans jamais calculer la projection. Les noyaux courants :
Le noyau radial\(K_{rbf}\) est gouverné par \(\sigma\) (= rbf_sigma) : un grand \(\sigma\) rend l’influence de chaque point locale (une frontière sinueuse), un petit \(\sigma\) la rend globale (une frontière lisse). Parce que chaque noyau compare des distances ou des produits scalaires, les prédicteurs doivent d’abord être standardisés — sinon un prédicteur exprimé dans de grandes unités dominerait le noyau.
🟢 Avec un agent IA
Un problème de classification et vous ne savez pas quel noyau convient ? Demandez à Prova« ajuste des SVM linéaire, radial et polynomial à ces données, règle le coût et le noyau par validation croisée, et dis-moi lequel généralise le mieux » — elle répond avec du code tidymodels + kernlab que vous pouvez exécuter sur vos propres données, puis vous aide à lire la courbe de réglage, les vecteurs de support, et l’exactitude et l’AUC sur le jeu de test. The runtime is the judge.Ask Prova →
Problèmes courants
Vous avez oublié de standardiser les prédicteurs. Le SVM mesure des distances, donc un prédicteur exprimé dans de grandes unités (p. ex. insulin) domine la marge et la frontière ignore tout le reste. Utilisez toujours step_normalize(all_numeric_predictors()) dans la recipe (ou appuyez-vous sur le scaled = TRUE de ksvm / e1071::svm(scale = TRUE)).
Vos données comportent des valeurs manquantes.na.omit() supprime les lignes incomplètes (utilisé ici), mais vous perdez des données. Préférez l’imputation à l’intérieur de la recipe — step_impute_median(all_numeric_predictors()) — pour qu’aucune ligne ne soit jetée et que l’imputation soit apprise uniquement à partir de l’entraînement.
Le SVM RBF surapprend (excellent en entraînement, médiocre en test). Cela signifie généralement que rbf_sigma est trop grand (la frontière est trop sinueuse) ou que cost est trop élevé. Ajustez les deux par validation croisée et préférez l’extrémité plus souple et plus lisse ; ne les fixez pas à la main.
Vous avez besoin de probabilités prédites, pas seulement de classes. Un SVM simple renvoie une classe ferme. Demandez au moteur des probabilités — ksvm(..., prob.model = TRUE) puis predict(type = "probabilities"), ou en tidymodels predict(type = "prob") (kernlab ajuste un modèle de probabilité interne). Lisez-les dans l’évaluation des modèles de classification.
Deux exécutions donnent des résultats légèrement différents. Le découpage des plis de validation croisée et l’aléa interne de kernlab sont aléatoires. Appelez set.seed() avant vfold_cv() et l’ajustement pour un résultat reproductible.
Questions fréquentes
NoteComment faire un support vector machine en R ?
Utilisez kernlab::ksvm() ou e1071::svm() directement, ou la route tidymodels pour un workflow ajustable. La manière tidymodels : svm_rbf(cost = tune(), rbf_sigma = tune()) |> set_engine("kernlab") |> set_mode("classification") à l’intérieur d’un workflow avec step_normalize(), ajusté par tune_grid() sur des plis de validation croisée et finalisé avec last_fit(). Standardisez toujours d’abord les prédicteurs — le SVM mesure des distances.
NoteComment construire un classifieur SVM en R ?
Découpez les données (rsample::initial_split()), normalisez les prédicteurs dans une recipe(), choisissez une spécification parsnip — svm_linear(), svm_poly() ou svm_rbf() sur le moteur "kernlab" — regroupez-les dans un workflow(), ajustez le cost (et rbf_sigma/degree) par tune_grid() sur une CV à 10 plis, puis finalize_workflow() et last_fit() pour évaluer l’exactitude et l’AUC ROC une fois sur le jeu de test. Le classique one-liner est ksvm(diabetes ~ ., data = train, kernel = "rbfdot", C = 1).
NoteQue fait le paramètre de coût C dans un SVM ?
C contrôle la souplesse de la marge. Un petit C autorise davantage de violations de marge — une frontière plus large, plus indulgente, qui généralise habituellement mieux. Un grand C punit chaque point d’entraînement mal classé — une frontière plus serrée qui colle plus fort aux données d’entraînement et peut surapprendre. Vous choisissez C par validation croisée ; sur des données réelles bruitées, un petit C à marge souple l’emporte souvent (c’est le cas sur les données Pima ici).
Commencez par un noyau linéaire (svm_linear) : il est rapide, robuste, et souvent suffisant, surtout avec de nombreux prédicteurs. S’il sous-apprend, essayez le noyau radial / RBF (svm_rbf) — le choix non linéaire standard, flexible et lisse, en ajustant à la fois cost et rbf_sigma. Utilisez un noyau polynomial (svm_poly) lorsque vous attendez une frontière polynomiale spécifique. Ajustez toujours par validation croisée et comparez sur le même jeu de test mis de côté ; quand les noyaux sont à égalité, préférez le plus simple.
NoteQue sont les vecteurs de support dans un SVM ?
Les vecteurs de support sont les points d’entraînement situés le plus près de la frontière de décision — sur, ou à l’intérieur de, la marge. Ce sont les seuls points qui définissent la frontière : supprimer n’importe quel autre point ne la déplacerait pas du tout. C’est pourquoi les SVM sont robustes et économes en mémoire — le modèle se résume à un petit ensemble de cas frontaliers décisifs. ksvm() indique combien de vecteurs de support il a conservés.
Testez vos connaissances
ImportantExercice : ajuster un SVM radial et le comparer au linéaire
En utilisant les données PimaIndiansDiabetes2 (mlbench, avec na.omit()), construisez un SVM radial (RBF) à la manière tidymodels : découpez 80/20 stratifié sur diabetes, normalisez les prédicteurs, ajustez costetrbf_sigma par validation croisée à 10 plis sur l’exactitude, et rapportez l’exactitude et l’AUC ROC sur le jeu de test. Comment se compare-t-il au SVM linéaire de la leçon ?
AstuceIndice
La forme est identique au workflow linéaire — changez uniquement la spécification en svm_rbf(cost = tune(), rbf_sigma = tune()) et passez une grille remplissant l’espace grid = 15 (ou un grid_regular) à tune_grid(). Vous aurez besoin de rsample, recipes, parsnip, workflows, tune, dials, et yardstick.
Vous obtiendrez une exactitude et une AUC d’environ ~0.72 / ~0.80 pour le noyau radial — un cran en dessous du SVM linéaire à ~0.76 / ~0.84, et non au-dessus. La frontière Pima est proche du linéaire, donc la flexibilité supplémentaire du noyau radial n’apporte rien ici — sa frontière plus sinueuse coûte en fait un peu, et le simple SVM linéaire est le meilleur choix par défaut. Sur des données à frontière véritablement courbe, le noyau RBF prendrait l’avantage.
Vérification rapide. Vous standardisez les prédicteurs et ajustez un SVM radial. Un collègue ajuste le même SVM sur les prédicteurs bruts, non mis à l’échelle, et obtient une frontière bien pire qui semble ignorer la plupart des variables. Qu’est-ce qui a mal tourné, et quel est le correctif ?
NoteAfficher la réponse
Le collègue a sauté la standardisation. Le noyau d’un SVM mesure des distances entre points, donc un prédicteur enregistré dans de grandes unités (p. ex. insulin dans les centaines) domine chaque distance, et les prédicteurs exprimés dans de petites unités (p. ex. pedigree) sont effectivement ignorés. Le correctif est de mettre tous les prédicteurs à la même échelle d’abord — step_normalize(all_numeric_predictors()) dans la recipe, ou scaled = TRUE dans ksvm / scale = TRUE dans e1071::svm. Après la mise à l’échelle, chaque prédicteur contribue équitablement à la marge.
Conclusion
Vous avez construit des classifieurs support vector machine de bout en bout sur les données PimaIndiansDiabetes2. Un SVM trouve la frontière à marge maximale, définie par ses vecteurs de support ; le noyau (linéaire, polynomial, radial) décide si cette frontière est droite ou courbe ; le coût C règle la souplesse de la marge, et le rbf_sigma du RBF règle à quel point la courbe est sinueuse. Vous avez standardisé d’abord, ajusté par validation croisée avec le workflow moderne parsnip + kernlab (et vu les routes classiques ksvm() / svm()), lu la courbe de réglage, tracé la frontière de décision, et évalué l’exactitude et l’AUC ROC sur un jeu de test mis de côté. La règle pratique : standardisez, commencez linéaire, laissez la validation croisée choisir le coût et le noyau, et comparez toujours — ici, le noyau linéaire (et polynomial) a égalé ou battu le radial, donc livrez le plus simple qui tient le coup.
Prouvez que vous savez le faire. Maîtrisez toute la série Classification en R — suivez votre parcours, construisez des projets et obtenez un certificat.
Cette leçon est reproductible : chaque métrique, frontière et figure a été produite par le code montré — copiez n’importe quel bloc et exécutez-le pour les reproduire. The runtime is the judge.
Références
James, G., Witten, D., Hastie, T., & Tibshirani, R. (2014). An Introduction to Statistical Learning, with Applications in R. Springer. (Chapitre 9 — Support Vector Machines.)
Karatzoglou, A., Smola, A., Hornik, K., & Zeileis, A. (2004). kernlab — An S4 Package for Kernel Methods in R. Journal of Statistical Software, 11(9). (Le package kernlab.)
Kuhn, M., & Silge, J. Tidy Modeling with R. En ligne, gratuit (CC BY-NC-SA).