将RDD转换为具有固定长度文件数据的向量

时间:2015-12-02 02:41:18

标签: scala apache-spark rdd

我是Spark + Scala的新手,仍然在发展我的直觉。我有一个包含许多数据样本的文件。每2048行代表一个新样本。我试图将每个样本转换为一个向量,然后运行k-means聚类算法。数据文件如下所示:

123.34  800.18
456.123 23.16
...

当我玩一小部分数据时,我会从文件中创建一个RDD,如下所示:

val fileData = sc.textFile("hdfs://path/to/file.txt")

然后使用以下代码创建向量:

val freqLineCount = 2048
val numSamples    = 200
val freqPowers = fileData.map( _.split(" ")(1).toDouble )
val allFreqs    = freqPowers.take(numSamples*freqLineCount).grouped(freqLineCount)
val lotsOfVecs  = allFreqs.map(spec => Vectors.dense(spec) ).toArray
val lotsOfVecsRDD = sc.parallelize( lotsOfVecs ).cache()

val numClusters = 2
val numIterations = 2
val clusters = KMeans.train(lotsOfVecsRDD, numClusters, numIterations)

这里的关键是我可以在一个字符串数组上调用.grouped并返回一个包含连续2048值的数组数组。然后,转换为向量并通过KMeans训练算法运行它是微不足道的。

我正在尝试在更大的数据集上运行此代码并遇到java.lang.OutOfMemoryError: Java heap space错误。大概是因为我在我的freqPowers变量上调用了take方法,然后对该数据执行了一些操作。

我将如何实现在此数据集上运行KMeans的目标,并牢记

  1. 每个数据样本在文件中每2048行发生一次(因此该文件应按顺序进行解析)

  2. 此代码需要在分布式群集上运行

  3. 我不需要耗尽内存:)

  4. 提前致谢

1 个答案:

答案 0 :(得分:1)

您可以执行以下操作:

val freqLineCount = 2048
val freqPowers = fileData.flatMap(_.split(" ")(1).toDouble)

// Replacement of your current code.
val groupedRDD = freqPowers.zipWithIndex().groupBy(_._2 / freqLineCount)
val vectorRDD = groupedRDD.map(grouped => Vectors.dense(grouped._2.map(_._1).toArray))

val numClusters = 2
val numIterations = 2
val clusters = KMeans.train(vectorRDD, numClusters, numIterations)

替换代码使用zipWithIndex()和long的除法将RDD元素分组为freqLineCount块。分组后,所讨论的元素被提取到它们的实际向量中。