【Spark MLlib】(四)K-Means 聚类分析

使用 Spark 机器学习库来做机器学习工作,可以说是非常的简单,通常只需要在对原始数据进行处理后,然后直接调用相应的 API 就可以实现。但是要想选择合适的算法,高效准确地对数据进行分析,可能还需要深入了解下算法原理,以及相应 Spark MLlib API 实现的参数的意义,本文带你了解 K-means 聚类算法。

一、K-means 聚类算法原理

何谓聚类,聚类指的是将数据分类到不同的类或者簇这样的一个过程,所以同一个簇中的对象有很大的相似性,而不同簇间的对象有很大的相异性,聚类与分类的不同在于,聚类所要求划分的类是未知的。

聚类分析是一个无监督学习 (Unsupervised Learning) 过程, 一般是用来对数据对象按照其特征属性进行分组,经常被应用在客户分群,欺诈检测,图像分析等领域。K-means 应该是最有名并且最经常使用的聚类算法了,其原理比较容易理解,并且聚类效果良好,有着广泛的使用。

和诸多机器学习算法一样,K-means 算法也是一个迭代式的算法,其主要步骤如下:

  • 第一步,选择 K 个点作为初始聚类中心。
  • 第二步,计算其余所有点到聚类中心的距离,并把每个点划分到离它最近的聚类中心所在的聚类中去。在这里,衡量距离一般有多个函数可以选择,最常用的是欧几里得距离 (Euclidean Distance), 也叫欧式距离。
  • 第三步,重新计算每个聚类中所有点的平均值,并将其作为新的聚类中心点。
  • 第四步,重复 (二)、(三) 步的过程,直至聚类中心不再发生改变,或者算法达到预定的迭代次数,又或聚类中心的改变小于预先设定的阀值。

在实际应用中,K-means 算法有两个不得不面对并且克服的问题。

  • 聚类个数 K 的选择。K 的选择是一个比较有学问和讲究的步骤,我们会在后文专门描述如何使用 Spark 提供的工具选择 K。
  • 初始聚类中心点的选择。选择不同的聚类中心可能导致聚类结果的差异。

Spark MLlib K-means 算法的实现在初始聚类点的选择上,借鉴了一个叫 K-means||的类 K-means++ 实现。K-means++ 算法在初始点选择上遵循一个基本原则: 初始聚类中心点相互之间的距离应该尽可能的远。基本步骤如下:

  • 第一步,从数据集 X 中随机选择一个点作为第一个初始点。
  • 第二步,计算数据集中所有点与最新选择的中心点的距离 D(x)。
  • 第三步,选择下一个中心点,使得最大。
  • 第四部,重复 (二)、(三) 步过程,直到 K 个初始点选择完成。

二、K-means 实现

Spark MLlib 中 K-means 算法的实现类 (KMeans.scala) 具有以下参数,具体如下:

class KMeans private (
    private var k: Int,
    private var maxIterations: Int,
    private var runs: Int,
    private var initializationMode: String,
    private var initializationSteps: Int,
    private var epsilon: Double,
    private var seed: Long) extends Serializable with Logging
  • k 表示期望的聚类的个数。
  • maxInterations 表示方法单次运行最大的迭代次数。
  • runs 表示算法被运行的次数。K-means 算法不保证能返回全局最优的聚类结果,所以在目标数据集上多次跑 K-means 算法,有助于返回最佳聚类结果。
  • initializationMode 表示初始聚类中心点的选择方式, 目前支持随机选择或者 K-means||方式。默认是 K-means||。
  • initializationSteps表示 K-means||方法中的部数。
  • epsilon 表示 K-means 算法迭代收敛的阀值。
  • seed 表示集群初始化时的随机种子。

运行示例

import org.apache.spark.mllib.clustering.KMeans
import org.apache.spark.mllib.linalg
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.rdd.RDD
 
object KmeansSpark {
 
  def main(args: Array[String]): Unit = {
 
    //在本地启动Spark
    val sparkConf = new SparkConf().setMaster("local[2]").setAppName("KmeansSpark")
    val sc = new SparkContext(sparkConf)
 
    //加载本地文件数据形成RDD
    val data = sc.textFile("file:///root/test.txt")
    val parsedData: RDD[linalg.Vector] = data.map(s=>{
      val values: Array[Double] = s.split(" ").map(x => x.toDouble)
      Vectors.dense(values)
    })
 
    //聚类中心个数
    val numClusters = 8
    //算法迭代次数
    val numIterations = 20
    //算法运行次数
    val runs = 10
    //KMeans训练
    val kmeansModel = KMeans.train(parsedData, numClusters, numIterations, runs)
 
    //打印聚类中心ID
    kmeansModel.clusterCenters.foreach(x=>{
     println(x)
    })
    //打印数据归属哪个聚类中心ID
    parsedData.map(v => v.toString + " belong to cluster: " +kmeansModel.predict(v))
    ss.foreach(x=>
      println(x)
    )
    sc.stop()
  
  }
}

三、K值的选择

前面提到 K 的选择是 K-means 算法的关键,Spark MLlib 在 KMeansModel 类里提供了 computeCost 方法,该方法通过计算所有数据点到其最近的中心点的平方和来评估聚类的效果。一般来说,同样的迭代次数和算法跑的次数,这个值越小代表聚类的效果越好。但是在实际情况下,我们还要考虑到聚类结果的可解释性,不能一味的选择使 computeCost 结果值最小的那个 K。

val ks:Array[Int] = Array(3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20)
ks.foreach(cluster => {
 val model:KMeansModel = KMeans.train(parsedData, cluster,30,1)
 val ssd = model.computeCost(parsedData)
 println("sum of squared distances of points to their nearest center when k=" + cluster + " -> "+ ssd)
})
K-means 算法是一种无监督学习算法,用于将数据集分成 K 个簇。Spark MLlib 中实现了 K-means 算法,可以用于大规模数据的。 以下是 Spark MLlib 实现 K-means 算法的基本步骤: 1. 加载数据集,将数据集转换为特征向量 2. 初始化 K 个簇的质心 3. 对每个样本,将其分配到距离最近的簇 4. 根据分配结果,重新计算每个簇的质心 5. 重复步骤 3 和 4,直到达到最大迭代次数或收敛 以下是一个简单的代码示例: ```python from pyspark.ml.clustering import KMeans from pyspark.ml.evaluation import ClusteringEvaluator from pyspark.ml.feature import VectorAssembler # 加载数据集 data = spark.read.format("csv").load("path/to/data.csv", header=True, inferSchema=True) # 转换数据集为特征向量 assembler = VectorAssembler(inputCols=data.columns, outputCol="features") dataset = assembler.transform(data) # 初始化 KMeans 模型 kmeans = KMeans().setK(2).setSeed(1) # 训练模型 model = kmeans.fit(dataset) # 输出簇中心点 centers = model.clusterCenters() for center in centers: print(center) # 预测数据集中每个样本所属的簇 predictions = model.transform(dataset) # 评估模型 evaluator = ClusteringEvaluator() silhouette = evaluator.evaluate(predictions) print("Silhouette with squared euclidean distance = " + str(silhouette)) ``` 这里假设数据集已经被加载并且包含两个特征。首先,使用 VectorAssembler 将数据集转换为特征向量。然后,初始化 KMeans 模型并训练它。最后,输出每个簇的中心点和模型评估结果。需要注意的是,这里使用了默认的欧几里得距离作为距离度量。如果需要使用其他距离度量,可以通过设置 distanceMeasure 参数来实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值