2

我正在使用 Spark (v1.1.0) 和 Scala 的 MLlib 对具有点(经度和纬度)的文件进行 k-means 聚类。我的文件包含用逗号分隔的 4 个字段(最后两个是经度和纬度)。

这里是使用 Spark 的 k-means 聚类示例: https ://spark.apache.org/docs/1.1.0/mllib-clustering.html

我想要做的是读取 HDFS 中特定目录中文件的最后两个字段,将它们转换为RDD<Vector>o 在 KMeans 类中使用此方法: train(RDD<Vector> data, int k, int maxIterations)

这是我的代码:

val data = sc.textFile("/user/test/location/*") val parsedData = data.map(s => Vectors.dense(s.split(',').map(fields => (fields(2).toDouble,fields(3).toDouble))))

但是当我在 spark-shell 中运行它时,出现以下错误:

错误:重载方法值与替代方案密集:(值:Array [Double])org.apache.spark.mllib.linalg.Vector(firstValue:Double,otherValues:Double *)org.apache.spark.mllib.linalg.Vector不能应用于 (Array[(Double, Double)])

所以,我不知道如何将我的 Array[(Double, Double)] 转换为 Array[Double]。也许还有另一种方法可以读取这两个字段并将它们转换为RDD<Vector>,有什么建议吗?

4

3 回答 3

1
val parsedData = data.map(s => Vectors.dense(s.split(',').flatMap(fields => Array(fields(2).toDouble,fields(3).toDouble))))
于 2014-12-07T10:18:50.670 回答
1

密集向量有两种“工厂”方法:

def dense(values: Array[Double]): Vector
def dense(firstValue: Double, otherValues: Double*): Vector

虽然上面提供的类型是Array[Tuple2[Double,Double]]并且因此不类型匹配:(
提取上面的逻辑:)

val parseLineToTuple: String => Array[(Double,Double)] = s => s=> s.split(',').map(fields => (fields(2).toDouble,fields(3).toDouble))

这里需要的是从输入字符串中创建一个新的数组,如下所示:(再次只关注特定的解析逻辑)

val parseLineToArray: String => Array[Double] = s=> s.split(",").flatMap(fields => Array(fields(2).toDouble,fields(3).toDouble)))

将其集成到原始代码中应该可以解决问题:

val data = sc.textFile("/user/test/location/*")
val vectors = data.map(s => Vectors.dense(parseLineToArray(s))

(您当然可以内联该代码,我在这里将其分开以专注于手头的问题)

于 2014-12-06T12:34:47.920 回答
1

先前使用 flatMap 的建议是基于您想要映射 .split(",") 给出的数组元素的假设 - 并通过使用 Array 而不是 Tuple2 来满足类型。

.map/.flatMap 函数接收到的参数是原始集合的一个元素,因此为清楚起见应命名为“字段”(单数)。调用 fields(2) 选择拆分的每个元素的第三个字符 - 因此是混乱的根源。

如果您要的是 .split(",") 数组的第 3 个和第 4 个元素,则转换为 Double:

s.split(",").drop(2).take(2).map(_.toDouble)

或者,如果您希望将所有但第一个字段转换为 Double(如果可能超过 2 个):

s.split(",").drop(2).map(_.toDouble)
于 2014-12-08T07:35:28.407 回答