聚类算法之K-Means算法Spark实践
Posted 计算姬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了聚类算法之K-Means算法Spark实践相关的知识,希望对你有一定的参考价值。
聚类算法常被用于数据量非常大的应用中。我们都知道,机器学习算法大体分为三类:监督学习(supervised learning)、无监督学习(unsupervised learning)和半监督学习(semi-supervised learning)。监督学习是指我们利用带有类别属性标注的数据去训练、学习,用于预测未知数据的类别属性。例如,根据用户之前的购物行为去预测用户是否会购买某一商品。常用的算法有决策树,支持向量机SVM,朴素贝叶斯分类器,K-近邻算法KNN,线性回归和逻辑回归等,相信大家在学习机器学习算法的过程中已经耳熟能详。无监督学习是指在无人工干预的情况下将数据按照相似程度划分,而聚类算法就是非常典型的无监督学习方法,通常要处理的数据没有标签信息,可以通过计算数据之间的相似性来自动划分类别。
K-Means算法
这里要介绍的K-Means算法是聚类分析中最基础的一个聚类算法,算法的思想是初始随机给定K个簇中心,按照距离最近原则把待分类的样本点分到各个簇,然后按平均法重新计算各个簇的质心,从而确定新的簇心,迭代计算,直到簇心的移动距离小于某个给定的误差值。使用算法描述语言,只要四个步骤:
任意选择K个点作为初始聚类中心;
计算每个样本点到聚类中心的距离,将每个样本点划分到离该点最近的聚类中去;
计算每个聚类中所有点的坐标平均值,并将这个平均值作为新的聚类中心;
反复执行2、3,直到聚类中心的移动小于某误差值或者聚类次数达到要求为止。
这里计算距离的方法通常是计算欧几里得距离,假设中心点center是(x1, y1),需要计算的样本点point是(x2, y2):
另外,给出损失函数(Cost Function),每一次选取好新的中心点,我们就要计算一下当前选好的中心点损失为多少,这个损失代表着偏移量,越大说明当前聚类的效果越差,计算公式称为(Within-Cluster Sum of Squares, WCSS):
其中,xi表示某一对象,ck表示该对象所属类别的中心点。整个式子的含义就是对各个类别下的对象,求对象与中心点的欧式距离的平方,把所有的平方求和就是L(C)。
测试数据:
0.0 0.0
0.1 0.1
0.2 0.2
3.0 3.0
3.1 3.1
3.2 3.2
9.0 9.0
9.1 9.1
9.2 9.2
Scala版KMeans代码示例:
import org.apache.spark.mllib.clustering.KMeans
import org.apache.spark.mllib.linalg.Vectors
import org.apache.spark.{SparkConf, SparkContext}
object KMeansTest {
def main(args: Array[String]) {
val conf = new SparkConf()
val sc = new SparkContext(conf)
val data =sc.textFile(args(0))
val parsedData =data.map(s => Vectors.dense(s.split(' ').map(_.trim.toDouble))).cache()
//设置簇的个数为3
val numClusters =3
//迭代20次
val numIterations= 20
//运行10次,选出最优解
val runs=10
//设置初始K选取方式为k-means++
val initMode = "k-means||"
val clusters = new KMeans().
setInitializationMode(initMode).
setK(numClusters).
setMaxIterations(numIterations).
run(parsedData)
//打印出测试数据属于哪个簇
println(parsedData.map(v=> v.toString() + " belong to cluster :" +clusters.predict(v)).collect().mkString(" "))
// Evaluateclustering by computing Within Set Sum of Squared Errors
val WSSSE = clusters.computeCost(parsedData)
println("WithinSet Sum of Squared Errors = " + WSSSE)
val a21 =clusters.predict(Vectors.dense(1.2,1.3))
val a22 =clusters.predict(Vectors.dense(4.1,4.2))
//打印出中心点
println("Clustercenters:")
for (center <-clusters.clusterCenters) {
println(" "+ center)
}
println("Prediction of (1.2,1.3)-->"+a21)
println("Prediction of (4.1,4.2)-->"+a22)
}
}
提交spark执行(standalone):
spark-submit --class KMeansTest --master local[4] KMeansTest.jar ../data/kmeans_data.txt
结果:
[0.0,0.0] belong to cluster :0
[0.1,0.1] belong to cluster :0
[0.2,0.2] belong to cluster :0
[3.0,3.0] belong to cluster :2
[3.1,3.1] belong to cluster :2
[3.2,3.2] belong to cluster :2
[9.0,9.0] belong to cluster :1
[9.1,9.1] belong to cluster :1
[9.2,9.2] belong to cluster :1
WithinSet Sum of Squared Errors = 0.12000000000007648
Clustercenters:
[0.1,0.1]
[9.1,9.1]
[3.1,3.1]
Prediction of (1.2,1.3)-->0
Prediction of (4.1,4.2)-->2
K-Means算法有两个重大缺陷:
K-Means属于无监督学习,最大的特别和优势在于模型的建立不需要训练数据。在日常工作中,很多情况下没有办法事先获取到有效的训练数据,这时采用K-Means是一个不错的选择。K值是预先给定的,属于预先知识,很多情况下K值的估计是非常困难的,对于像计算全部微信用户的交往圈这样的场景就完全的没办法用K-Means进行。对于可以确定K值不会太大但不明确精确的K值的场景,可以进行迭代运算,然后找出Cost Function最小时所对应的K值,这个值往往能较好的描述有多少个簇类。
K-Means算法对初始选取的聚类中心点是敏感的,不同的随机种子点得到的聚类结果完全不同。可以用K-Means++算法来解决这个问题。
K-Means++算法
K-Means++算法选择初始聚类中心的思想是:初始的聚类中心之间的相互距离要尽可能远。算法步骤如下:
随机挑选一个点作为第一个聚类中心;
对于每一个点x,计算和其最近的一个聚类中心的距离D(x),将所有距离求和得到Sum(D(x));
然后,再取一个随机值,用权重的方式来取计算下一个“种子点”。这个算法的思想是,先取一个能落在Sum(D(x))中的随机值Random,然后用Random -= D(x),直到其<=0,此时的点就是下一个“种子点”(其思想是,D(x)较大的点,被选取作为聚类中心的概率较大);
重复2和3,直到K个聚类中心被选出来;
利用这K个初始聚类中心进行K-Means算法。
Spark的MLlib库中也支持K-Means++初始化方法,只需增加初始模式设置:
val initMode = "k-means||"
val clusters = new KMeans().
setInitializationMode(initMode).
setK(numClusters).
setMaxIterations(numIterations).
run(parsedData)
在构成圆形的5000个随机样本点上,设置7个簇,分别使用K-Means算法和K-Means++算法的聚类对比图如下:
Fig 1. K-Means聚类结果
Fig 2. K-Means++聚类结果
可以看出使用K-Means++算法优化初始聚类中心可以使得划分的类别较好。
当然,如果想彻底不用设置K值也是有很多算法来支持的,从聚类算法衍生出一派的社区发现(Community Detection)算法,在社区发现算法中,点表示网络中的成员,边代表成员之间由于共同的兴趣而构成的相似性连接。聚类和社区发现算法之间最大的不同在于,社区发现中的点被网络连接到了一起,而聚类中的数据点并没有构成网络。关于社区发现算法,这是我的博士研究课题,有空再表。
参考资料:(本文算法请戳阅读原文)
《Spark MLlib机器学习-算法、源码及实战详解》黄美灵著
http://sobuhu.com/ml/2012/11/25/kmeans-python.html
http://coolshell.cn/articles/7779.html
http://rosettacode.org/wiki/K-means%2B%2B_clustering
六一儿童节快乐!
以上是关于聚类算法之K-Means算法Spark实践的主要内容,如果未能解决你的问题,请参考以下文章
Spark2.0机器学习系列之8: 聚类分析(K-Means,Bisecting K-Means,LDA,高斯混合模型)