Linear Support Vector Classifier
A linear support vector machine fits the maximum-margin straight boundary between the two classes — the widest possible corridor separating them, rather than logistic regression’s best-fit log-odds line.
R equivalent
library(e1071)
set.seed(1)
n <- 200
amount <- c(rnorm(n / 2, mean = 40, sd = 15), rnorm(n / 2, mean = 220, sd = 60))
velocity <- c(rpois(n / 2, 2), rpois(n / 2, 9))
fraud <- factor(c(rep(0, n / 2), rep(1, n / 2)))
train <- data.frame(amount, velocity, fraud)
model <- svm(fraud ~ amount + velocity, data = train, kernel = "linear",
cost = 1, scale = TRUE, probability = TRUE)
print(model)
new_cases <- data.frame(amount = c(35, 260), velocity = c(1, 10))
pred <- predict(model, new_cases, probability = TRUE)
attr(pred, "probabilities")
Console output:
Call:
svm(formula = fraud ~ amount + velocity, data = train, kernel = "linear",
cost = 1, probability = TRUE, scale = TRUE)
Parameters:
SVM-Type: C-classification
SVM-Kernel: linear
cost: 1
Number of Support Vectors: 8
0 1
1 0.9945590041 0.005440996
2 0.0001001911 0.999899809
Tool equivalent:
Jube.Service.Repository.AnalyticsTrainingRun.AdvancedAnalyticsLinearSupportVectorClassifierTrainingService / tool
SubmitLinearSupportVectorClassifierTraining — Kind = Classifier, recall class LinearSupportVectorClassifierRecall.
Complexity (default 1.0) is cost above; Standardise (default true) is scale = TRUE. The background worker fits
the boundary with a dual coordinate-descent solver rather than e1071’s SMO, then extracts a plain weight vector and
bias — recall is a single dot product, not a stored-support-vector search, so the snapshot is as small as logistic
regression’s. The raw signed distance to the boundary is not a probability and is Platt-calibrated (Calibrate,
DecisionThreshold) exactly as e1071’s own probability = TRUE does internally above.
Code audit
AdvancedAnalyticsLinearSupportVectorClassifierTrainingService delegates to
LinearSupportVectorClassifierTrainer.TrainWithSplit
(Jube.Engine/AdvancedAnalytics/Classification/LinearSupportVectorClassifierTrainer.cs:62-315), which instantiates
Accord.MachineLearning.VectorMachines.Learning.LinearDualCoordinateDescent (lines 19, 152-156).
- Solver:
LinearDualCoordinateDescent(Accord.MachineLearning/VectorMachines/Learning/LinearDualCoordinateDescent.cs:157-187) is a coordinate descent algorithm ported from LIBLINEAR’ssolve_l2r_l1l2_svc(class remarks, lines 97-99, 103-105, citing Hsieh et al., ICML 2008, Algorithm 3) — not Sequential Minimal Optimization, unlike the kernel SVM family that sits beside it in the same training-service group. Its defaults, none overridden by the trainer:Loss = Loss.L2(squared hinge loss, the default field value,BaseLinearDualCoordinateDescentfieldloss = Loss.L2at line 365),Tolerance = 0.1(line 359),max_iter = 1000(line 357). The trainer sets onlyComplexityandToken(LinearSupportVectorClassifierTrainer.cs:152-156). - Kernel: fixed to
Linearby construction —LinearDualCoordinateDescent.Createalways builds aSupportVectorMachine(inputs) { Kernel = kernel }with the library’sLinearkernel type (LinearDualCoordinateDescent.cs:183-186); there is no kernel option on this DTO to diverge from, unlike the kernel SVM and kernel ridge families. - Weight/bias extraction:
machine.SupportVectors[0]is cloned as the weight vector andmachine.Thresholdas the bias (LinearSupportVectorClassifierTrainer.cs:178-179). For this solver the fitted model has exactly one “support vector” entry, which is really the dense weight vector itself (Model.SupportVectors = new[] { kernel.CreateVector(w) },BaseLinearDualCoordinateDescent.InnerRun,LinearDualCoordinateDescent.cs:454-456) — not a set of retained training rows. This confirms the existing mapping’s claim that recall is a single dot product, not a stored-vector search. - Reported support vector count is separate from the stored weight vector:
SupportVectorCount(LinearSupportVectorClassifierTrainer.cs:180) is computed from the solver’s own Lagrange multipliers (learner.Lagrange.Count(a => a > LagrangeMultiplierFloor), floor1e-9) — a genuine per-row sparsity count from the dual solution, decoupled from the single weight vector actually persisted. - Divergence guard: the trainer checks every weight and the bias for finiteness and throws before returning a model
if any are non-finite (lines 182-185) — a defence against the coordinate descent solver diverging on separable data at
too high a
Complexity;LinearDualCoordinateDescentitself has no such guard of its own. - Probability: the raw decision value
w·x + biasis Platt-calibrated byJube.Analytics.PlattCalibration.Fiton the validation split (LinearSupportVectorClassifierTrainer.cs:212) — the same custom calibrator used by every classifier family in this section, not the vendoredAccord.MachineLearning.VectorMachines.Learning.Probabilistic.ProbabilisticOutputCalibration. - Seeding:
Accord.Math.Random.Generator.ThreadSeedis set tooptions.Seedfor the duration oflearner.Learnand restored in afinallyblock (lines 159-174). The solver’s internalrandomfield (BaseLinearDualCoordinateDescent.InnerRun,LinearDualCoordinateDescent.cs:437, passed into itsDualSvmSolver) reads fromAccord.Math.Random.Generator’s thread-static instance, so this is a real, load-bearing seeding mechanism for reproducing a fit, not a decorative option. - Class imbalance is unweighted: the trainer warns when the training split is imbalanced beyond 100:1
(
SevereImbalanceRatio, lines 35, 260-266) because the solver is not given per-class weights (Cp/Cnin the class’s own dual formulation remarks) — both classes share the same upper bound derived fromComplexity.
