目录
Spark机器学习库简介
K-means聚类算法原理
K-means 实现
运行示例
K值的选择
MLlib是Spark的机器学习(ML)库。其目标是使实用的机器学习可扩展且简单。从较高的层面来说,它提供了以下工具:
使用 Spark 机器学习库来做机器学习工作,可以说是非常的简单,通常只需要在对原始数据进行处理后,然后直接调用相应的 API 就可以实现。但是要想选择合适的算法,高效准确地对数据进行分析,您可能还需要深入了解下算法原理,以及相应 Spark MLlib API 实现的参数的意义。
何谓聚类,聚类指的是将数据分类到不同的类或者簇这样的一个过程,所以同一个簇中的对象有很大的相似性,而不同簇间的对象有很大的相异性,聚类与分类的不同在于,聚类所要求划分的类是未知的。
聚类分析是一个无监督学习 (Unsupervised Learning) 过程, 一般是用来对数据对象按照其特征属性进行分组,经常被应用在客户分群,欺诈检测,图像分析等领域。K-means 应该是最有名并且最经常使用的聚类算法了,其原理比较容易理解,并且聚类效果良好,有着广泛的使用。
和诸多机器学习算法一样,K-means 算法也是一个迭代式的算法,其主要步骤如下:
在实际应用中,K-means 算法有两个不得不面对并且克服的问题。
Spark MLlib K-means 算法的实现在初始聚类点的选择上,借鉴了一个叫 K-means||的类 K-means++ 实现。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
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-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)
})