Как преобразовать Array [(Double, Double)] в Array [Double] в Scala?

Я использую MLlib of Spark (v1.1.0) и Scala для кластеризации k-средних значений, применяемой к файлу с точками (долгота и широта). Мой файл содержит 4 поля, разделенных запятой (последние два - долгота и широта).

Вот пример кластеризации k-средних с использованием Spark: 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))))

Но когда я запускаю его в искровой оболочке, я получаю следующую ошибку:

ошибка: значение перегруженного метода, заполненное альтернативами: (значения: Array [Double]) org.apache.spark.mllib.linalg.Vector (firstValue: Double, otherValues: Double *) org.apache.spark.mllib.linalg.Vector не может применяться к (Array [(Double, Double)])

Итак, я не знаю, как преобразовать мой массив [(Double, Double)] в Array [Double]. Может быть, есть другой способ прочитать два поля и преобразовать их в RDD<Vector>, какие-нибудь предложения?


person artemisa    schedule 06.12.2014    source источник


Ответы (3)


Предыдущее предложение с использованием flatMap было основано на предположении, что вы хотите отобразить элементы массива, заданного .split (","), и предлагало удовлетворить типы, используя Array вместо Tuple2.

Аргумент, полученный функциями .map / .flatMap, является элементом исходной коллекции, поэтому для ясности должен называться «field» (singleluar). Вызов поля (2) выбирает 3-й символ каждого из элементов разделения - отсюда и источник путаницы.

Если вам нужен 3-й и 4-й элементы массива .split (","), преобразованные в Double:

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

или если вы хотите, чтобы все поля, НО первые, были преобразованы в Double (если их может быть больше 2):

s.split(",").drop(2).map(_.toDouble)
person ectrop    schedule 08.12.2014

Есть два "фабричных" метода для плотных векторов:

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))

(Вы, конечно, можете встроить этот код, я выделил его здесь, чтобы сосредоточиться на рассматриваемой проблеме)

person maasg    schedule 06.12.2014

person    schedule
comment
Я сделал это, но это не работает. Один из примеров моего файла: 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 до конец, а затем он превращает их в двойные. Что мне нужно, так это взять только последние два поля моего файла. - person artemisa; 07.12.2014