如何在 Scala 中将 Array[(Double, Double)] 转换为 Array[Double]?
Posted
技术标签:
【中文标题】如何在 Scala 中将 Array[(Double, Double)] 转换为 Array[Double]?【英文标题】:How to transform Array[(Double, Double)] into Array[Double] in Scala? 【发布时间】:2015-02-04 13:13:49 【问题描述】:我正在使用 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>
,有什么建议吗?
【问题讨论】:
【参考方案1】:之前使用 flatMap 的建议是基于您想要映射 .split(",") 给出的数组元素的假设 - 并通过使用 Array 而不是 Tuple2 来满足类型。
.map/.flatMap 函数接收到的参数是原始集合的一个元素,因此为了清楚起见应命名为“字段”(单数)。调用 fields(2) 选择拆分的每个元素的第三个字符 - 因此是混乱的根源。
如果您要的是 .split(",") 数组的第 3 和第 4 个元素,则转换为 Double:
s.split(",").drop(2).take(2).map(_.toDouble)
或者如果您希望将所有 BUT 字段转换为 Double(如果可能超过 2 个):
s.split(",").drop(2).map(_.toDouble)
【讨论】:
【参考方案2】:密集向量有两种“工厂”方法:
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))
(您当然可以内联该代码,我在这里将其分开以专注于手头的问题)
【讨论】:
【参考方案3】:val parsedData = data.map(s => Vectors.dense(s.split(',').flatMap(fields => Array(fields(2).toDouble,fields(3).toDouble))))
【讨论】:
我已经这样做了,但它不起作用。我的文件的一个示例是:point1,green,30.6894754264,-17.543308253 但是当我应用上面的代码时,结果是:parsedData.take(1) Array[org.apache.spark.mllib.linalg.Vector] = Array([108.0,97.0,108.0,97.0,46.0,54.0,55.0,46.0])
这就像它需要我文件的每个字段并且它应用 flatMap 方法并从位置获取字符2 到最后,然后将它们转换为 double。我只需要获取文件的最后两个字段。以上是关于如何在 Scala 中将 Array[(Double, Double)] 转换为 Array[Double]?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Scala 中将 Spark DataFrames 一一添加到 Seq()