KMEANS ||用于Spark的情绪分析

时间:2016-01-05 16:43:57

标签: scala apache-spark machine-learning k-means apache-spark-mllib

我正在尝试编写基于Spark的情绪分析程序。为此,我使用word2vec和KMeans群集。从word2Vec我在100维空间中有20k字/向量集合,现在我正在尝试聚类这个向量空间。当我使用默认的并行实现运行KMeans时,算法工作了3个小时!但随机初始化策略就像8分钟。 我究竟做错了什么?我有4台内核处理器和16 GB RAM的mac book pro机器。

K~ = 4000 maxInteration为20

var vectors: Iterable[org.apache.spark.mllib.linalg.Vector] =
      model.getVectors.map(entry => new VectorWithLabel(entry._1, entry._2.map(_.toDouble)))
    val data = sc.parallelize(vectors.toIndexedSeq).persist(StorageLevel.MEMORY_ONLY_2)
    log.info("Clustering data size {}",data.count())
    log.info("==================Train process started==================");
    val clusterSize = modelSize/5

    val kmeans = new KMeans()
    kmeans.setInitializationMode(KMeans.K_MEANS_PARALLEL)
    kmeans.setK(clusterSize)
    kmeans.setRuns(1)
    kmeans.setMaxIterations(50)
    kmeans.setEpsilon(1e-4)

    time = System.currentTimeMillis()
    val clusterModel: KMeansModel = kmeans.run(data)

火花上下文初始化在这里:

val conf = new SparkConf()
      .setAppName("SparkPreProcessor")
      .setMaster("local[4]")
      .set("spark.default.parallelism", "8")
      .set("spark.executor.memory", "1g")
    val sc = SparkContext.getOrCreate(conf)

关于运行此程序的更新也很少。我在Intelij IDEA里面运行它。我没有真正的Spark集群。但我认为你的个人机器可以是Spark集群

我看到程序在Spark代码LocalKMeans.scala:

的循环中挂起
// Initialize centers by sampling using the k-means++ procedure.
    centers(0) = pickWeighted(rand, points, weights).toDense
    for (i <- 1 until k) {
      // Pick the next center with a probability proportional to cost under current centers
      val curCenters = centers.view.take(i)
      val sum = points.view.zip(weights).map { case (p, w) =>
        w * KMeans.pointCost(curCenters, p)
      }.sum
      val r = rand.nextDouble() * sum
      var cumulativeScore = 0.0
      var j = 0
      while (j < points.length && cumulativeScore < r) {
        cumulativeScore += weights(j) * KMeans.pointCost(curCenters, points(j))
        j += 1
      }
      if (j == 0) {
        logWarning("kMeansPlusPlus initialization ran out of distinct points for centers." +
          s" Using duplicate point for center k = $i.")
        centers(i) = points(0).toDense
      } else {
        centers(i) = points(j - 1).toDense
      }
    }

2 个答案:

答案 0 :(得分:1)

使用KMeans.K_MEANS_PARALLEL初始化比random更复杂。但是,它不应该产生如此大的差异。我建议调查一下,是否需要花费很多时间的并行算法(它实际上应该比KMeans本身更有效)。

有关分析的信息,请参阅: http://spark.apache.org/docs/latest/monitoring.html

如果不是占用时间的初始化则存在严重错误。但是,使用随机初始化对最终结果来说不应该更糟(效率更低!)。

实际上,当您使用KMeans.K_MEANS_PARALLEL初始化时,您应该通过0次迭代获得合理的结果。如果不是这种情况,那么在发送KMeans的数据分布中可能存在一些规律性。因此,如果您没有随机分发数据,您也可以更改此信息。但是,这样的影响会让我感到惊讶,我会给出一定数量的迭代。

答案 1 :(得分:1)

我在AWS上运行了3个从站(c3.xlarge)的火花,结果是一样的 - 问题是并行KMeans在N个并行运行中初始化算法,但它对于小的仍然非常慢数据量,我的解决方案是使用随机初始化。 数据大小约为:4k簇,用于21k 100-dim向量。