【Spark ML系列】 Kmeans聚类算法由来原理方法示例源码分析

本文详细介绍了 Spark 中 KMeans 聚类算法的由来、原理,包括 K-means++ 的初始化过程,以及如何在 Spark 中使用 KMeans 进行聚类,包括 RDD 和 DataFrame 版本的示例。文章还探讨了 KMeans 的参数,如聚类数目、初始化算法、优化方法等,并提供了源码分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spark Kmeans聚类算法由来原理方法示例源码分析 点击这里免费看全文


K-means++ 是一种改进的 K-means 聚类算法,旨在选择更好的初始聚类中心点。以下是 Spark 中 K-means++ 的全面介绍

由来

传统的 K-means 算法是通过随机选择初始聚类中心点来开始聚类过程。然而,随机选择的初始中心可能导致收敛到局部最优解的风险增加,即结果聚类质量较差。

为了解决这个问题,Arthur 和 Vassilvitskii 在 2007 年提出了 K-means++ 算法。它使用一种概率性的方法来选择初始聚类中心,从而使得初始中心能够更好地代表数据集,减少陷入局部最优解的可能性。

原理

K-means++ 的初始化过程如下:

  1. 从数据集中随机选择一个样本作为第一个聚类中心。
  2. 对于每个样本,计算它与已选择的聚类中心的最短距离(即到最近的聚类中心的距离)。
  3. 根据每个样本与已选择的聚类中心的最短距离,以概率分布的方式选择下一个聚类中心。距离较远的样本被选择为下一个聚类中心的概率较大。
  4. 重复步骤 2 和 3,直到选择出 k 个聚类中心。

K-means++ 的核心思想是通过引入概率选择机制,使得选择的初始聚类中心在整个数据集中分布更加均匀。这样做的好处是能够更好地代表数据集,从而改善最终聚类结果的质量。

在 Spark 中,K-means++ 算法被用作默认的初始化算法,它可以通过设置 initMode 参数为 "k-means||" 来启用。通过使用 K-means++ 初始化算法,Spark 能够提供更可靠和高质量的聚类结果。

示例RDD版

import org.apache.spark.mllib.clustering.{
   KMeans, KMeansModel}
import org.apache.spark.mllib.linalg.Vectors

// Load and parse the data
val data = sc.textFile("data/mllib/kmeans_data.txt")
val parsedData = data.map(s => Vectors.dense(s.split(' ').map(_.toDouble))).cache()

// Cluster the data into two classes using KMeans
val numClusters = 2
val numIterations = 20
val clusters = KMeans.train(parsedData, numClusters, numIterations)

// Evaluate clustering by computing Within Set Sum of Squared Errors
val WSSSE = clusters.computeCost(parsedData)
println(s"Within Set Sum of Squared Errors = $WSSSE")

// Save and load model
clusters.save(sc, "target/org/apache/spark/KMeansExample/KMeansModel")
val sameModel = KMeansModel.load(sc, "target/org/apache/spark/KMeansExample/KMeansModel")

示例DataFrame版本

import org.apache.spark.ml.clustering.KMeans
import org.apache.spark.ml.evaluation.ClusteringEvaluator

// Loads data.
val dataset = spark.read.format("libsvm").load("data/mllib/sample_kmeans_data.txt")

// Trains a k-means model.
val kmeans = new KMeans().setK(2).setSeed(1L)
val model = kmeans.fit(dataset)

// Make predictions
val predictions = model.transform(dataset)

// Evaluate clustering by computing Silhouette score
val evaluator = new ClusteringEvaluator()

val silhouette = evaluator.evaluate(predictions)
println(s"Silhouette with squared euclidean distance = $silhouette")

// Shows the result.
println("Cluster Centers: ")
model.clusterCenters.foreach(println)

方法详细说明

  • load:从指定路径加载 KMeans 模型。

    • load(path: String): KMeansModel
    • 从指定路径加载保存的 KMeans 模型。
    • 参数:
      • path:模型的保存路径。
    • 返回值:KMeansModel 对象,表示加载的 KMeans 模型。
  • read:返回一个用于读取 KMeans 模型的 MLReader 对象。

    • read(): MLReader[KMeansModel]
    • 返回一个用于读取 KMeans 模型的 MLReader 对象。
    • 返回值:MLReader[KMeansModel] 对象,用于读取 KMeans 模型。
  • k:获取聚类数目(k)的参数。

    • k: IntParam
    • 获取聚类数目(k)的参数。注意,实际返回的聚类数目可能少于 k,例如如果数据集中的不同点数量少于 k。
    • 返回值:IntParam 对象,表示聚类数目。
  • initMode:获取初始化算法的参数。

    • initMode: Param[String]
    • 获取初始化算法的参数。可以选择 “random” 以随机选择初始聚类中心,或选择 “k-means||” 使用 k-means++ 的并行变种算法。
    • 返回值:Param[String] 对象,表示初始化算法。
  • initSteps:获取 k-means|| 初始化模式的步数参数。

    • initSteps: IntParam
    • 获取 k-means|| 初始化模式的步数参数。这是一个高级设置,通常默认值 2 已经足够。
    • 返回值:IntParam 对象,表示初始化步数。
  • solver:获取优化方法的参数。

    • solver: Param[String]
    • 获取用于优化的方法的参数。支持的选项有:“auto”、“row” 和 “block”。默认为 “auto”。
    • 返回值:Param[String] 对象,表示优化方法。
  • maxBlockSizeInMB:获取将输入数据堆叠到块中的最大内存限制的参数。

    • maxBlockSizeInMB: DoubleParam
    • 获取将输入数据堆叠到块中的最大内存限制的参数。默认值为 0.0,表示自动选择最佳值。
    • 返回值:DoubleParam 对象,表示最大内存限制。
  • weightCol:获取权重列名的参数。

    • weightCol: Param[String]
    • 获取权重列名的参数。如果未设置或为空,则将所有实例权重视为 1.0。
    • 返回值:Param[String] 对象,表示权重列名。
  • distanceMeasure:获取距离度量的参数。

    • distanceMeasure: Param[String]
    • 获取距离度量的参数。支持的选项有:“euclidean” 和 “cosine”。
    • 返回值:Param[String] 对象,表示距离度量。
  • tol:获取迭代算法的收敛容忍度的参数。

    • tol: DoubleParam
    • 获取迭代算法的收敛容忍度的参数。必须大于等于 0。
    • 返回值:DoubleParam 对象,表示容忍度。
  • predictionCol:获取预测结果列名的参数。

    • predictionCol: Param[String]
    • 获取预测结果列名的参数。
    • 返回值:Param[String] 对象,表示预测结果列名。
  • seed:获取随机种子的参数。

    • seed: LongParam
    • 获取随机种子的参数。
    • 返回值:LongParam 对象,表示随机种子。
  • featuresCol:获取特征列名的参数。

    • featuresCol: Param[String]
    • 获取特征列名的参数。
    • 返回值:Param[String] 对象,表示特征列名。
  • maxIter:获取最大迭代次数的参数。

    • maxIter: IntParam
    • 获取最大迭代次数的参数。必须大于等于 0。
    • 返回值:IntParam 对象,表示最大迭代次数。
  • uid:获取对象的唯一 ID。

    • uid: String
    • 获取对象及其派生对象的不可变唯一 ID。
    • 返回值:String,表示对象的唯一 ID。
  • copy:创建一个具有相同 UID 和额外参数的当前实例的副本。

    • copy(extra: ParamMap): KMeans
    • 创建当前实例的副本,并带有相同的 UID 和额外的参数。
    • 参数:
      • extra:ParamMap 对象,用于指定额外的参数。
    • 返回值:KMeans 对象的副本。
  • fit:将模型应用于输入数据,拟合出一个模型。

    • fit(dataset: Dataset[_]): KMeansModel
    • 将模型应用于输入数据,并拟合出一个 KMeansModel 模型。
    • 参数:
      • dataset:要拟合的输入数据集。
    • 返回值:KMeansModel 对象,表示拟合得到的 KMeans 模型。
  • transformSchema:检查转换的有效性,并根据输入模式推导出输出模式。

    • transformSchema(schema: StructType): StructType
    • 检查转换的有效性,并根据输入模式推导出输出模式。
    • 参数:
      • schema:输入数据的模式。
    • 返回值:StructType 对象,表示输出数据的模式。

中文源码

object KMeans

/**
 * 用于调用K-means聚类的顶层方法。
 */
@Since("0.8.0")
object KMeans {
   

  // 初始化模式名称
  @Since("0.8.0")
  val RANDOM = "随机"
  @Since("0.8.0")
  val K_MEANS_PARALLEL = "k-means||"

  /**
   * 使用给定的参数训练一个K-means模型。
   *
   * @param data 训练数据点,作为`Vector`类型的RDD。
   * @param k 要创建的簇的数量。
   * @param maxIterations 允许的最大迭代次数。
   * @param initializationMode 初始化算法。可以是"random"或"k-means||"。(默认值:"k-means||")
   * @param seed 随机种子用于簇初始化。默认是基于系统时间生成种子。
   */
  @Since("2.1.0")
  def train(
      data: RDD[Vector],
      k: Int,
      maxIterations: Int,
      initializationMode: String,
      seed: Long): KMeansModel = {
   
    new KMeans().setK(k)
      .setMaxIterations(maxIterations)
      .setInitializationMode(initializationMode)
      .setSeed(seed)
      .run(data)
  }

  /**
   * 使用给定的参数训练一个K-means模型。
   *
   * @param data 训练数据点,作为`Vector`类型的RDD。
   * @param k 要创建的簇的数量。
   * @param maxIterations 允许的最大迭代次数。
   * @param initializationMode 初始化算法。可以是"random"或"k-means||"。(默认值:"k-means||")
   */
  @Since("2.1.0")
  def train(
      data: RDD[Vector],
      k: Int,
      maxIterations: Int,
      initializationMode: String): KMeansModel = {
   
    new KMeans().setK(k)
      .setMaxIterations(maxIterations)
      .setInitializationMode(initializationMode)
      .run(data)
  }

  /**
   * 使用给定的参数训练一个K-means模型。
   *
   * @param data 训练数据点,作为`Vector`类型的RDD。
   * @param k 要创建的簇的数量。
   * @param maxIterations 允许的最大迭代次数。
   * @param runs 从Spark 2.0.0开始,此参数不起作用。
   * @param initializationMode 初始化算法。可以是"random"或"k-means||"。(默认值:"k-means||")
   * @param seed 随机种子用于簇初始化。默认是基于系统时间生成种子。
   */
  @Since("1.3.0")
  @deprecated("使用不带'runs'参数的train方法", "2.1.0")
  def train(
      data: RDD[Vector],
      k: Int,
      maxIterations: Int,
      runs: Int,
      initializationMode: String,
      seed: Long): KMeansModel = {
   
    new KMeans().setK(k)
      .setMaxIterations(maxIterations)
      .setInitializationMode(initializationMode)
      .setSeed(seed)
      .run(data)
  }

  /**
   * 使用给定的参数训练一个K-means模型。
   *
   * @param data 训练数据点,作为`Vector`类型的RDD。
   * @param k 要创建的簇的数量。
   * @param maxIterations 允许的最大迭代次数。
   * @param runs 从Spark 2.0.0开始,此参数不起作用。
   * @param initializationMode 初始化算法。可以是"random"或"k-means||"。(默认值:"k-means||")
   */
  @Since("0.8.0")
  @deprecated("使用不带'runs'参数的train方法", "2.1.0")
  def train(
      data: RDD[Vector],
      k: Int,
      maxIterations: Int,
      runs: Int,
      initializationMode: String): KMeansModel = {
   
    new KMeans().setK(k)
      .setMaxIterations(maxIterations)
      .setInitializationMode(initializationMode)
      .run(data)
  }

  /**
   * 使用指定的参数和未指定参数的默认值训练一个K-means模型。
   */
  @Since("0.8.0")
  def train(
      data: RDD[Vector],
      k: Int,
      maxIterations: Int): KMeansModel = {
   
    new KMeans().setK(k)
      .setMaxIterations(maxIterations)
      .run(data)
  }

  /**
   * 使用指定的参数和未指定参数的默认值训练一个K-means模型。
   */
  @Since("0.8.0")
  @deprecated("使用不带'runs'参数的train方法", "2.1.0"
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BigDataMLApplication

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值