习题 14:KMeans 算法

题目:使用 Spark 机器学习库完成无监督 KMeans 聚类任务,读取 LIBSVM 格式数据文件 input/sample_kmeans_data.txt,同时评测聚类指标。

sample_kmeans_data.txt

0 1:2.496714 2:1.861736
0 1:2.647689 2:3.523030
0 1:1.765847 2:1.765863
0 1:3.579213 2:2.767435
0 1:1.530526 2:2.542560
0 1:1.536582 2:1.534270
0 1:2.241962 2:0.086720
0 1:0.275082 2:1.437712
0 1:0.987169 2:2.314247
import org.apache.spark.ml.clustering.KMeans
import org.apache.spark.ml.evaluation.ClusteringEvaluator
import org.apache.spark.ml.linalg.Vectors
import org.apache.spark.sql.SparkSession

object KMeansExample {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder()
      .appName("KMeansExample")
      .master("local[*]")
      .getOrCreate()

    // 1. 读取 LIBSVM 格式数据
    val dataset = spark.read.format("libsvm").load("input/sample_kmeans_data.txt")

    println("原始数据预览:")
    dataset.show(false)

    // 2. 训练 KMeans 模型(设定 k=2,可根据实际调整)
    val kmeans = new KMeans()
      .setK(2)
      .setSeed(1L)
      .setFeaturesCol("features")

    val model = kmeans.fit(dataset)

    // 3. 获取聚类中心
    println("聚类中心:")
    model.clusterCenters.foreach(println)

    // 4. 对数据进行预测
    val predictions = model.transform(dataset)

    // 5.1 轮廓系数(Silhouette Score,值越接近 1 越好)
    val evaluator = new ClusteringEvaluator()
      .setFeaturesCol("features")
      .setPredictionCol("prediction")
      .setDistanceMeasure("squaredEuclidean")
    val silhouetteScore = evaluator.evaluate(predictions)
    println(s"轮廓系数(Silhouette Score)= $silhouetteScore")

    // 5.2 簇内平方和(WCSS / Within Set Sum of Squared Errors)
    val wcss = predictions.select("features", "prediction").rdd.map { row =>
      val features = row.getAs[org.apache.spark.ml.linalg.Vector](0)
      val clusterIdx = row.getInt(1)
      val center = model.clusterCenters(clusterIdx)
      Vectors.sqdist(features, center)
    }.sum()
    println(s"簇内平方和(WCSS)= $wcss")

    println("预测结果预览:")
    predictions.select("features", "prediction").show(false)

    spark.stop()
  }
}