Spark 机器学习-实例演示- K-Means《二》

来源:互联网 发布:linux打tar包 编辑:程序博客网 时间:2024/05/22 00:07


1.K-Means简介

K-Means 是聚类的一个算法,是一个无监督学习,目标是将一部分实体根据某种意义上的相似度 和另一部分实体聚在一起。聚类通常被用于探索性的分析。 
K-Means将n个观察实例分类到k个聚类中,以使得每个观察实例 距离它所在的聚类的中心点比其他的聚类中心点的距离更近。所 
以它是一种基于距离的迭代式算法。

 算法:
1 选择 K 个点作为初始中心 
2 将每个点指派到最近的中心 , 形成 K 个簇 ( 聚类 ) 
3 重新计算每个簇的中心 
4 重复 2 - 3 直至中心不发生变化 
即:
① 在所有点(向量)中随机抽取出k个点(向量),作为初始聚类中心点,然后遍历其余的点(向量),找到距离各自最近的聚类中心点, 
将其加到该聚类中。
②求出每个聚类的中心点作为新的聚类中心,然后再遍历所有的 观测点,找到距离其最近的中心点,加到该聚类中。重复运行
此步骤。
③当新产生的中心点与前一个中心点一致或者变化不大时,认为 迭代结束。

距离
– 绝对值距离
– 欧氏距离
– 闵可夫斯基距离
– 切比雪夫距离
– 马氏距离


迭代结束条件有很多种,比如:



MLlib K-Means 的实现中包含一个 k-means ++ 方法的并行化变体 kmeans || 。
MLlib 里面的实现有如下的参数:
k 是所需的类簇的个数。
maxI terations 是最大的迭代次数。
initiali z ationMode 这个参数决定了是用随机初始化还是通过 k-means || 进行初始化。
runs 是跑 k-means 算法的次数( k-mean 算法不能保证能找出最优解,如果在给定的数据集上运行多次,算法将会返回最佳的结果)。
initiali z iationSteps 决定了 k-means || 算法的步数。
epsilon 决定了判断 k-means 是否收敛的距离阀值。

2.数据格式



3.示例程序
[plain] view plain copy
  1. import org.apache.log4j.{Level, Logger}  
  2. import org.apache.spark.{SparkConf, SparkContext}  
  3. import org.apache.spark.mllib.clustering.KMeans  
  4. import org.apache.spark.mllib.linalg.Vectors  
  5.   
  6. object Kmeans {  
  7.   def main(args: Array[String]) {  
  8.     //屏蔽不必要的日志显示在终端上  
  9.     Logger.getLogger("org.apache.spark").setLevel(Level.WARN)  
  10.     Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)  
  11.   
  12.     // 设置运行环境  
  13.     val conf = new SparkConf().setAppName("Kmeans").setMaster("local[4]")  
  14.     val sc = new SparkContext(conf)  
  15.   
  16.     //装载数据集  
  17.     val data = sc.textFile("/home/mmicky/IdeaProjects/machine-learning/kmeans_data.txt", 1)  
  18.     val parsedData = data.map(s => Vectors.dense(s.split(' ').map(_.toDouble)))  
  19.   
  20.     //将数据集聚类,2个类,20次迭代,形成数据模型  
  21.     val numClusters = 2  
  22.     val numIterations = 20  
  23.     val model = KMeans.train(parsedData, numClusters, numIterations)  
  24.   
  25.     //数据模型的中心点  
  26.     println("Cluster centers:")  
  27.     for (c <- model.clusterCenters) {  
  28.       println(" " + c.toString)  
  29.     }  
  30.   
  31.     //使用误差平方之和来评估数据模型  
  32.     val cost = model.computeCost(parsedData)  
  33.     println("Within Set Sum of Squared Errors = " + cost)  
  34.   
  35.     //使用模型测试单点数据  
  36.     println("Vectors 0.2 0.2 0.2 is belongs to clusters:" + model.predict(Vectors.dense("0.2 0.2 0.2".split(' ').map(_.toDouble))))  
  37.     println("Vectors 0.25 0.25 0.25 is belongs to clusters:" + model.predict(Vectors.dense("0.25 0.25 0.25".split(' ').map(_.toDouble))))  
  38.     println("Vectors 8 8 8 is belongs to clusters:" + model.predict(Vectors.dense("8 8 8".split(' ').map(_.toDouble))))  
  39.   
  40.     //交叉评估1,只返回结果  
  41.     val testdata = data.map(s => Vectors.dense(s.split(' ').map(_.toDouble)))  
  42.     val result1 = model.predict(testdata)  
  43.     result1.saveAsTextFile("/home/mmicky/IdeaProjects/machine-learning/result1")  
  44.   
  45.     //交叉评估2,返回数据集和结果  
  46.     val result2 = data.map {  
  47.       line =>  
  48.         val linevectore = Vectors.dense(line.split(' ').map(_.toDouble))  
  49.         val prediction = model.predict(linevectore)  
  50.         line + " " + prediction  
  51.     }.saveAsTextFile("/home/mmicky/IdeaProjects/machine-learning/result2")  
  52.   
  53.     sc.stop()  
  54.   }  
  55. }  

4.运行结果








5.R语言展示




6.用Scala实现K-Means算法

[plain] view plain copy
  1. package cn.chinahadoop.ml  
  2.   
  3. /**  
  4.  * Created by chenchao on 14-3-24.  
  5.  */  
  6.   
  7. import java.util.Random  
  8. import org.apache.spark.util.Vector  
  9. import org.apache.spark.SparkContext._  
  10. import scala.collection.mutable.HashMap  
  11. import scala.collection.mutable.HashSet  
  12. import org.apache.spark.util.Vector  
  13.   
  14. /**  
  15.  * K-means clustering.  
  16.  * 此例子会生成1000个向量,每个向量包含十个数字,任务是要选定十个向量作为质心  
  17.  */  
  18. object KMeans {  
  19.   val N = 1000  
  20.   val R = 1000 // Scaling factor  
  21.   val D = 10  
  22.   val K = 10  
  23.   val convergeDist = 0.001  
  24.   val rand = new Random(42)  
  25.   
  26.   def generateData = {  
  27.     def generatePoint(i: Int) = {  
  28.       Vector(D, _ => rand.nextDouble * R)  
  29.     }  
  30.     Array.tabulate(N)(generatePoint)  
  31.   }  
  32.   
  33.   def closestPoint(p: Vector, centers: HashMap[Int, Vector]): Int = {  
  34.     var index = 0  
  35.     var bestIndex = 0  
  36.     var closest = Double.PositiveInfinity  
  37.   
  38.     for (i <- 1 to centers.size) {  
  39.       val vCurr = centers.get(i).get  
  40.       val tempDist = p.squaredDist(vCurr)  
  41.       if (tempDist < closest) {  
  42.         closest = tempDist  
  43.         bestIndex = i  
  44.       }  
  45.     }  
  46.     bestIndex  
  47.   }  
  48.   
  49.   def main(args: Array[String]) {  
  50.     val data = generateData //初始化数据点,以向量形式存在,包含1000个向量,每个向量包含十个数字点  
  51.     var points = new HashSet[Vector] //随机选取的十组向量作为质心  
  52.     var kPoints = new HashMap[Int, Vector] //初始质心,共有十个 即每个质心对应着一个向量, 即这里的质心  
  53.     var tempDist = 1.0  
  54.   
  55.     while (points.size < K) {  
  56.       points.add(data(rand.nextInt(N)))  
  57.     }  
  58.   
  59.     val iter = points.iterator  
  60.     for (i <- 1 to points.size) {  
  61.       kPoints.put(i, iter.next())  
  62.     }  
  63.   
  64.     println("Initial centers: " + kPoints)  
  65.   
  66.     while(tempDist > convergeDist) {  
  67.       //查找与每个向量距离最近的质心  
  68.       var closest = data.map (p => (closestPoint(p, kPoints), (p, 1)))  
  69.   
  70.       //把那些具有相同质心的向量聚合在一起  
  71.       var mappings = closest.groupBy[Int] (x => x._1)  
  72.   
  73.       //把具有相同质心的向量标量相加  
  74.       var pointStats = mappings.map(pair => pair._2.reduceLeft [(Int, (Vector, Int))] {case ((id1, (x1, y1)), (id2, (x2, y2))) => (id1, (x1 + x2, y1+y2))})  
  75.   
  76.       //找出十个新的质心  
  77.       var newPoints = pointStats.map {mapping => (mapping._1, mapping._2._1/mapping._2._2)}  
  78.   
  79.       //迭代收敛条件,即质心变化不大  
  80.       tempDist = 0.0  
  81.       for (mapping <- newPoints) {  
  82.         tempDist += kPoints.get(mapping._1).get.squaredDist(mapping._2)  
  83.       }  
  84.   
  85.       //将新质心放入kPoints  
  86.       for (newP <- newPoints) {  
  87.         kPoints.put(newP._1, newP._2)  
  88.       }  
  89.     }  
  90.   
  91.     println("Final centers: " + kPoints)  
  92.   }  
  93. }  

运行结果: