Извлечь значения столбцов Dataframe как список в Apache Spark

86

Я хочу преобразовать строковый столбец фрейма данных в список. В DataframeAPI я могу найти RDD, поэтому я попытался сначала преобразовать его обратно в RDD, а затем применить toArrayфункцию к RDD. В этом случае длина и SQL работают нормально. Однако результат, который я получил от RDD, заключен в квадратные скобки вокруг каждого такого элемента [A00001]. Мне было интересно, есть ли подходящий способ преобразовать столбец в список или способ удалить квадратные скобки.

Мы ценим любые предложения. Спасибо!

ЗАСТЕНЧИВЫЙ.
источник

Ответы:

117

Это должно вернуть коллекцию, содержащую единственный список:

dataFrame.select("YOUR_COLUMN_NAME").rdd.map(r => r(0)).collect()

Без сопоставления вы просто получите объект Row, который содержит все столбцы из базы данных.

Имейте в виду, что это, вероятно, даст вам список любого типа. ÏЕсли вы хотите указать тип результата, вы можете использовать .asInstanceOf [YOUR_TYPE] в r => r(0).asInstanceOf[YOUR_TYPE]сопоставлении

PS из-за автоматической конвертации можно пропустить .rddчасть.

TheMP
источник
3
По какой-то непонятной причине работает наоборот (Spark 2.1.0) collect().map(r => r(0))- есть ли у этого порядка недостатки?
Boern
Может быть медленнее - ваше решение сначала собирает все данные о драйвере, а затем выполняет сопоставление с драйвером (без помощи исполнителя), используя только вычислительную мощность одного драйвера.
TheMP
72

В Spark 2.x и Scala 2.11

Я бы подумал о 3 возможных способах преобразования значений определенного столбца в список.

Общие фрагменты кода для всех подходов

import org.apache.spark.sql.SparkSession

val spark = SparkSession.builder.getOrCreate    
import spark.implicits._ // for .toDF() method

val df = Seq(
    ("first", 2.0),
    ("test", 1.5), 
    ("choose", 8.0)
  ).toDF("id", "val")

Подход 1

df.select("id").collect().map(_(0)).toList
// res9: List[Any] = List(one, two, three)

Что происходит сейчас? Мы собираем данные для драйвера collect()и выбираем нулевой элемент из каждой записи.

Это не может быть отличным способом сделать это, давайте улучшим его с помощью следующего подхода.


Подход 2

df.select("id").rdd.map(r => r(0)).collect.toList 
//res10: List[Any] = List(one, two, three)

Как лучше? Мы распределили нагрузку на преобразование карты между рабочими, а не одним драйвером.

Я знаю rdd.map(r => r(0)), тебе не кажется элегантным. Итак, давайте рассмотрим это в следующем подходе.


Подход 3

df.select("id").map(r => r.getString(0)).collect.toList 
//res11: List[String] = List(one, two, three)

Здесь мы не конвертируем DataFrame в RDD. Посмотрите, mapон не примет r => r(0)(или _(0)) как предыдущий подход из-за проблем с кодировщиком в DataFrame. Так что продолжайте использовать, r => r.getString(0)и это будет рассмотрено в следующих версиях Spark.

Вывод

Все варианты дают одинаковый результат, но 2 и 3 эффективны, наконец, 3-й эффективен и элегантен (я думаю).

Блокнот Databricks

Mrsrinivas
источник
24

Я знаю, что данный и запрошенный ответ предполагается для Scala, поэтому я просто предоставляю небольшой фрагмент кода Python на тот случай, если пользователю PySpark интересно. Синтаксис аналогичен данному ответу, но для правильного отображения списка мне действительно нужно ссылаться на имя столбца во второй раз в функции сопоставления, и мне не нужен оператор select.

т.е. DataFrame, содержащий столбец с именем "Raw"

Чтобы получить каждое значение строки в "Raw", объединенное в список, где каждая запись является значением строки из "Raw", я просто использую:

MyDataFrame.rdd.map(lambda x: x.Raw).collect()
Эбби Собх
источник
4
Это дает список объектов Row. Что, если вам нужен список значений?
ThatDataGuy
Это дает список значений.
Эбби Собх 01
Спасибо, что поделились этим! Это отлично работает для меня, просто интересно, есть ли способ ускорить это, он работает довольно медленно
Mojgan Mazouchi
5

В Scala и Spark 2+ попробуйте следующее (при условии, что имя вашего столбца - «s»): df.select('s).as[String].collect

Kanielc
источник
3
sqlContext.sql(" select filename from tempTable").rdd.map(r => r(0)).collect.toList.foreach(out_streamfn.println) //remove brackets

это работает отлично

Шайна Раза
источник
1
List<String> whatever_list = df.toJavaRDD().map(new Function<Row, String>() {
    public String call(Row row) {
        return row.getAs("column_name").toString();
    }
}).collect();

logger.info(String.format("list is %s",whatever_list)); //verification

Поскольку никто не дал никакого решения на java (настоящий язык программирования), можете поблагодарить меня позже

user12910640
источник
0
from pyspark.sql.functions import col

df.select(col("column_name")).collect()

здесь collect - это функции, которые, в свою очередь, преобразуют его в список. Остерегайтесь использовать список на огромном наборе данных. Это снизит производительность. Хорошо бы проверить данные.

амарнатх прыщ
источник
0

Это ответ Java.

df.select("id").collectAsList();
вахбуна
источник
0

Обновленное решение со списком:

dataFrame.select("YOUR_COLUMN_NAME").map(r => r.getString(0)).collect.toList
Афанасиос Циарас
источник