1、kmean 背景
Spark的MLlib库提供了许多可用的聚类方法的实现,如 KMeans、高斯混合模型、Power Iteration Clustering(PIC)、隐狄利克雷分布(LDA) 以及 KMeans 方法的变种 二分KMeans(Bisecting KMeans) 和 流式KMeans(Streaming KMeans)等。
2、原理
K-means算法也被称为k-均值,是一种最广泛使用的聚类算法,也是其他聚类算法的基础,照数据之间的相似度,将N个对象的数据集划分为K个划分(K个簇),使类别内的数据相似度较大,而类别间的数据相似较小。
3、步骤
既然要划分为k个簇,因此算法首先随机的选择了k个对象,每个对象初始的代表了一个簇的中心。其他的对象就去计算它们与这k个中心的距离(这里距离就是相似度),离哪个最近就把它们丢给哪个簇。第一轮聚类结束后,重新计算每个簇的平均值,将N中全部元素按照新的中心重新聚类。这个过程不断的反复,使得每一个改进之后的划分都比之前效果好,直到准则函数收敛(聚类结果不再变化)。
1.根据给定的k值,选取k个样本点作为初始划分中心;
2.计算所有样本点到每一个划分中心的距离,并将所有样本点划分到距离最近的划分中心;
3.计算每个划分中样本点的平均值,将其作为新的中心;
循环进行2~3步直至达到最大迭代次数,或划分中心的变化小于某一预定义阈值
优缺点:
但是常规K-means有些缺点,其一是受初始值影响较大。下面这张图很好的解释了这个缺点,人眼一看就能看出来,如果是分为4个聚类,应该这么分为左边那样的,如果用K-means结果会是右边这样,明显不对,所以说受初始值的影响会比较大。
因为这个缺陷,所以有了Bisecting k-means(二分K均值)
二 Bisecting k-means
主要是为了改进k-means算法随机选择初始中心的随机性造成聚类结果不确定性的问题,而Bisecting k-means算法受随机选择初始中心的影响比较小。
先将所有点作为一个簇,然后将该簇一分为二。之后选择其中一个簇【具有最大SSE值的一个簇】继续进行划分,二分这个簇以后得到的2个子簇,选择2个子簇的总SSE最小的划分方法,这样能够保证每次二分得到的2个簇是比较优的(也可能是最优的)。
其中判断模型拟合度的指标
SSE(Sum of Squared Error),也就是误差平方和,它计算的是拟合数据和原始数据对应点的误差的平方和,它是用来度量聚类效果的一个指标。SSE越接近于0,说明模型选择和拟合更好,数据预测也越成功。
kmean 是一种硬聚类分类
名词解释:硬聚类即一定是属于某一个类,比如我有2个簇A和B,那么所有的对象要不属于A要不就属于B,不可能会有第三种可能。而软聚类,使用概率的方式,一个对象可以是60%属于A,40% 属于B,即不完全属于同一个分布,而是以不同的概率分属于不同的分布**。GMM(高斯混合模型)就是一种软聚类**
三 GMM(高斯混合模型)
它和K-Means的区别是,K-Means是算出每个数据点所属的簇,而GMM是计算出这些数据点分配到各个类别的概率。
GMM算法步骤如下:
GMM算法步骤如下:
1.猜测有 K 个类别、即有K个高斯分布。
2.对每一个高斯分布赋均值 μ 和方差 Σ 。
3.对每一个样本,计算其在各个高斯分布下的概率
4.每一个样本对某高斯分布的贡献可以由其下的概率表示。并把该样本对该高斯分布的贡献作为权重来计算加权的均值和方差以替代其原本的均值和方差。
5.重复3~4直到每一个高斯分布的均值和方差收敛。
SparkML中主要聚类有以下几种:
K-means
Latent Dirichlet allocation (LDA)
Bisecting k-means
Gaussian Mixture Model (GMM)
kmean
package ml.test
import org.apache.spark.ml.clustering.KMeans
import org.apache.spark.sql.SparkSession
/**
*
*/
object KMeansDemo {
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().master("local[2]").getOrCreate()
val df = spark.read.format("libsvm").load("kmeans_data.txt")
//setK设置要分为几个类 setSeed设置随机种子
val kmeans = new KMeans().setK(3).setSeed(1L)
//聚类模型
val model = kmeans.fit(df)
// 预测 即分配聚类中心
model.transform(df).show(false)
//聚类中心
model.clusterCenters.foreach(println)
// SSE误差平方和
println("SSE:"+model.computeCost(df))
}
}
BisectingKMeans二分K均值
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().master("local[2]").getOrCreate()
val df = spark.read.format("libsvm").load("kmeans_data.txt")
val kmeans = new BisectingKMeans().setK(3).setSeed(1)
//聚类模型
val model = kmeans.fit(df)
// 预测 即分配聚类中心
model.transform(df).show(false)
//聚类中心
model.clusterCenters.foreach(println)
}
GMM高斯混合模型
def main(args: Array[String]): Unit = {
val spark = SparkSession.builder().master("local[2]").getOrCreate()
val df = spark.read.format("libsvm").load("kmeans_data.txt")
val gmm = new GaussianMixture().setK(3).setSeed(0)
val model = gmm.fit(df)
for (i <- 0 until model.getK) {
//weight是各组成成分的权重
//cov是样本协方差矩阵
//mean是均值
println(s"Gaussian $i:\nweight=${model.weights(i)}\n" +
s"mu=${model.gaussians(i).mean}\nsigma=\n${model.gaussians(i).cov}\n")
}
//也可以使用这种方式输出:model.gaussiansDF.show(false)
}
注意: kmeans_data.txt 参照源码包例子程序和 文本输入
可以发现,使用kmeans和BisectingKMeans,GMM 聚类结果一般是不一样的。
spark on kmean 接口文档 链接
http://spark.apache.org/docs/1.6.1/api/scala/index.html#org.apache.spark.ml.clustering.KMeans
参考:http://bigdata-star.com/archives/1863