Implementing a Local SVM Classifier with Apache Spark MLlib

The input dataset follows a pipe-delimited format where the first field represents the binary class label, followed by a comma-separated list of numerical features. This structure maps directly to Spark’s LabeledPoint type, which expects a double-precision label paired with a dense feature vector.

A representative sample of the training set includes entries formatted as label|feature1,feature2,feature3,feature4. The corresponding evaluation subset contains both positive and negative classes to validate classification boundaries.

To execute this workflow locally, initialize a Spark configuration targeting the local cluster and establish a parallel context. Data ingestion involves reading text lines, splitting on the delimiter, converting string arrays into Double values, and wrapping them into LabeledPoint objects. Caching the RDD prevents redundant computation during iterative training and evaluation phases.

import org.apache.spark.mllib.classification.SVMWithSGD
import org.apache.spark.mllib.evaluation.BinaryClassificationMetrics
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.mllib.optimization.L1Updater
import org.apache.spark.mllib.regression.LabeledPoint
import org.apache.spark.{SparkConf, SparkContext}

object SVMPipelineExecutor {
  def main(args: Array[String]): Unit = {
    val sparkConf = new SparkConf()
      .setAppName("LocalSVMWorkflow")
      .setMaster("local")
      .set("spark.testing.memory", "2147480000")
    
    val context = new SparkContext(sparkConf)
    val rawInput = context.textFile("file:///D:\\var\\dataset.txt")

    val processedSamples = rawInput.map { line =>
      val segments = line.split("\\|")
      val targetLabel = segments(0).toDouble
      val featureArray = Vectors.dense(segments(1).split(",").map(_.toDouble))
      println(s"Parsed record -> Target: $targetLabel, Vectors: ${featureArray.toArray.mkString("[", ",", "]")}")
      LabeledPoint(targetLabel, featureArray)
    }.cache()

    val gradientOptimizer = new SVMWithSGD()
    gradientOptimizer.optimizer.setNumIterations(10)
      .setRegParam(0.1)
      .setUpdater(new L1Updater())

    val classificationModel = gradientOptimizer.run(processedSamples)

    val queryVector = Vectors.dense(6.6, 3.0, 4.4, 1.4)
    println(s"Evaluation query: ${queryVector.toArray.mkString(", ")}")
    val forecastResult = classificationModel.predict(queryVector)
    println(s"Forecast outcome: $forecastResult")

    val scorePairs = processedSamples.map { datum =>
      val computedPrediction = classificationModel.predict(datum.features)
      println(s"Verification -> Ground Truth: ${datum.label}, Calculated: $computedPrediction")
      (datum.label, computedPrediction)
    }

    val performanceEvaluator = new BinaryClassificationMetrics(scorePairs)
    val aucValue = performanceEvaluator.areaUnderROC()
    println(s"Area Under ROC: $aucValue")
  }
}

Model construction relies on Stochastic Gradient Descent with L1 regularization to enforce sparsity in the weight vector. Adjusting iteration counts and regularization strength directly impacts convergence behavoir and geenralization performance. After generating predictions on the cached training set, pair each ground-truth label with its corresponding output to construct a score-label tuple sequence. Feeding this sequence into BinaryClassificationMetrics computes the Receiver Operating Characteristic area under the curve, providing a quantitative measure of discriminative capability independent of arbitrary threshold selection. Feature normalization should be applied prior to vector assembly, as unscaled attributes can skew margin calculations during the optimization step.

Tags: Apache Spark Support Vector Machines Scala Machine Learning MLlib

Posted on Fri, 07 Aug 2026 16:59:20 +0000 by thryb