Spark入门之十:聚类算法之kmeans的简介以及使用

来源:互联网 发布:mac中文输入法全角 编辑:程序博客网 时间:2024/06/07 08:02
  1. 聚类算法

    聚类,Cluster analysis,有时也被翻译为簇类,其核心任务是:将一组目标object划分为若干个簇,每个簇之间的object尽可能的相似,簇与簇之间的 object尽可能的相异。聚类算法是机器学习(或者说是数据挖掘更合适)中重要的一部分,除了最为简单的K-Means聚类算法外,较常见的还有:层次 法(CURE、CHAMELEON等)、网格算法(STING、WaveCluster等)等等。

    较权威的聚类问题定义:所谓聚类问题,就是给定一个元素集合D,其中每个元素具有n个可观察属性,使用某种算法将D划分成k个子集,要求每个子集内部的元素之间相异度尽可能低,而不同子集的元素相异度尽可能高。其中每个子集叫做一个簇。

    与分类不同,分类是示例式学习,要求分类前明确各个类别,并断言每个元素映射到一个类别,而聚类是观察式学习,在聚类前可以不知道类别甚至不给定类别数量,是无监督学习的一种。目前聚类广泛应用于统计学、生物学、数据库技术和市场营销等领域,相应的算法也非常的多。

  2. K-Means
    K-Means属于基于平方误差的迭代重分配聚类算法,其核心思想十分简单:
    1. 随机选择K个中心点
    2. 计算所有点到这K个中心点的距离,选择距离最近的中心点为其所在的簇
    3. 简单的采用算术平均数(mean)来重新计算K个簇的中心
    4. 重复步骤2和3,直至簇类不在发生变化或者达到最大迭代值
    5. 输出结果
      K-Means算法的结果好坏依赖于对初始聚类中心的选择,容易陷入局部最优解,对K值的选择没有准则可依循,对异常数据较为敏感,只能处理数值属性的数据,聚类结构可能不平衡。
  3. Spark实现K-Means算法
    测试数据如下:
    0.0 0.0 0.0
    0.1 0.1 0.1
    0.2 0.2 0.2
    9.0 9.0 9.0
    9.1 9.1 9.1
    9.2 9.2 9.2
    如前文所述,测试数据不用带标签,数据分为3个维度。
  4. Scala版本的Spark代码
    package com.eric.spark.mllib.kmeans

    import org.apache.log4j.{Level, Logger}
    import org.apache.spark.mllib.clustering.KMeans
    import org.apache.spark.mllib.linalg.Vectors
    import org.apache.spark.{SparkConf, SparkContext}

    /**
    * 该程序主要通过kmeans算法对数据进行分类
    *执行方式:./spark-submit --master=spark://cloud25:7077 --class com.eric.spark.mllib.KMeansSample --executor-memory=2g /opt/cloud/spark-1.4.1-bin-hadoop2.6/lib/spark_scala.jar
    * Created by Eric on 2015/11/12.
    */
    object KMeansSample {
    def main(args: Array[String]) {
    Logger.getLogger("org.apache.spark").setLevel(Level.WARN)
    Logger.getLogger("org.eclipse.jetty.server").setLevel(Level.OFF)

    //设置环境
    val sparkConconf=new SparkConf().setAppName("KMeansSample")
    val sparkContext=new SparkContext(sparkConconf)

    //装载数据
    val fileData=sparkContext.textFile("/data/mllib/kmeans_data.txt",1)
    val parseData=fileData.map(record=>Vectors.dense(record.split(" ").map(_.toDouble)))

    //模型训练
    val dataModelNumber=2;
    val dataModelTrainTimes=20
    val model=KMeans.train(parseData,dataModelNumber,dataModelTrainTimes)

    //数据模型的中心点
    // 运行结果:
    // Cluster centers:
    // [0.1,0.1,0.1]
    // [9.1,9.1,9.1]
    println("Cluster centers:")
    for (c <- model.clusterCenters) {
    println(" " + c.toString)
    }

    //使用模型测试单点数据
    //运行结果
    // Vectors 0.2 0.2 0.2 is belongs to clusters:0
    // Vectors 0.25 0.25 0.25 is belongs to clusters:0
    // Vectors 8 8 8 is belongs to clusters:1
    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))))
    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))))
    println("Vectors 8 8 8 is belongs to clusters:" + model.predict(Vectors.dense("8 8 8".split(' ').map(_.toDouble))))


    //交叉评估1,只返回结果
    val testdata = fileData.map(s =>Vectors.dense(s.split(' ').map(_.toDouble)))
    val result1 = model.predict(testdata)
    result1.saveAsTextFile("/data/mllib/result1")

    //交叉评估2,返回数据集和结果
    val result2 = fileData.map {
    line =>
    val linevectore = Vectors.dense(line.split(' ').map(_.toDouble))
    val prediction = model.predict(linevectore)
    line + " " + prediction
    }.saveAsTextFile("/data/mllib/result2")

    sparkContext.stop()


    }
    }

  5. 最后
    K-Means属于无监督学习,最大的特别和优势在于模型的建立不需要训练数据。在日常工作中,很多情况下没有办法事先获取到有效的训练数据,这时
    采用K-Means是一个不错的选择。但K-Means需要预先设置有多少个簇类(K值),这对于像计算某省份全部电信用户的交往圈这样的场景就完全的没 办法用K-Means进行。对于可以确定K值不会太大但不明确精确的K值的场景,可以进行迭代运算,然后找出cost最小时所对应的K值,这个值往往能较 好的描述有多少个簇类。
0 0