Extraia os valores da coluna do Dataframe como lista no Apache Spark


86

Quero converter uma coluna de string de um quadro de dados em uma lista. O que posso encontrar na DataframeAPI é RDD, então tentei primeiro convertê-lo de volta para RDD e depois aplicar a toArrayfunção ao RDD. Nesse caso, o comprimento e o SQL funcionam perfeitamente. No entanto, o resultado que obtive do RDD tem colchetes em torno de cada elemento como este [A00001]. Eu queria saber se existe uma maneira apropriada de converter uma coluna em uma lista ou uma maneira de remover os colchetes.

Qualquer sugestão seria apreciada. Obrigado!


Respostas:


117

Isso deve retornar a coleção contendo uma lista única:

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

Sem o mapeamento, você obtém apenas um objeto Row, que contém todas as colunas do banco de dados.

Lembre-se de que isso provavelmente resultará em uma lista de qualquer tipo. Se você quiser especificar o tipo de resultado, você pode usar .asInstanceOf [YOUR_TYPE] no r => r(0).asInstanceOf[YOUR_TYPE]mapeamento

PS devido à conversão automática, você pode pular a .rddparte.


3
Por alguma razão estranha, funciona ao contrário (Spark 2.1.0) collect().map(r => r(0))- esta ordem tem alguma desvantagem?
Boern

Pode ser mais lento - sua solução primeiro coleta todos os dados do driver e, depois disso, faz o mapeamento do driver (sem ajuda do executor), usando apenas o poder de processamento de um único driver.
Niemand

72

Com Spark 2.xe Scala 2.11

Eu pensaria em três maneiras possíveis de converter valores de uma coluna específica em Lista.

Snippets de código comuns para todas as abordagens

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

Abordagem 1

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

O que acontece agora? Estamos coletando dados para o Driver collect()e escolhendo o elemento zero de cada registro.

Essa não poderia ser uma maneira excelente de fazer isso. Vamos melhorá-la na próxima abordagem.


Abordagem 2

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

Como está melhor? Distribuímos a carga de transformação do mapa entre os trabalhadores, em vez de um único driver.

Eu sei rdd.map(r => r(0))que não parece elegante você. Então, vamos abordar isso na próxima abordagem.


Abordagem 3

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

Aqui não estamos convertendo DataFrame em RDD. Observe mapque não aceita r => r(0)(ou _(0)) como a abordagem anterior devido a problemas de codificador no DataFrame. Então acabe usando r => r.getString(0)e seria abordado nas próximas versões do Spark.

Conclusão

Todas as opções dão a mesma saída, mas 2 e 3 são eficazes, finalmente o terceiro é eficaz e elegante (eu acho).

Caderno Databricks


24

Eu sei que a resposta dada e solicitada é presumida para Scala, então estou apenas fornecendo um pequeno trecho de código Python no caso de um usuário PySpark estar curioso. A sintaxe é semelhante à resposta fornecida, mas para abrir a lista corretamente, na verdade, preciso fazer referência ao nome da coluna uma segunda vez na função de mapeamento e não preciso da instrução select.

ou seja, um DataFrame, contendo uma coluna chamada "Raw"

Para obter cada valor de linha em "Raw" combinado como uma lista em que cada entrada é um valor de linha de "Raw", simplesmente uso:

MyDataFrame.rdd.map(lambda x: x.Raw).collect()

4
Isso fornece uma lista de objetos Row. E se você quiser uma lista dos valores?
ThatDataGuy

Isso fornece uma lista de valores.
abby sobh

Obrigado por compartilhar isso! Isso funciona muito bem para mim, apenas me perguntando se há uma maneira de acelerar isso, ele está muito lento
Mojgan Mazouchi

5

No Scala e no Spark 2+, tente isso (assumindo que o nome da coluna seja "s"): df.select('s).as[String].collect


3
sqlContext.sql(" select filename from tempTable").rdd.map(r => r(0)).collect.toList.foreach(out_streamfn.println) //remove brackets

funciona perfeitamente


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

Já que ninguém deu nenhuma solução em java (Real Programming Language) Pode me agradecer depois


0
from pyspark.sql.functions import col

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

aqui, coletar são funções que, por sua vez, o convertem em lista. Cuidado ao usar a lista do enorme conjunto de dados. Isso diminuirá o desempenho. É bom verificar os dados.


0

Esta é a resposta java.

df.select("id").collectAsList();

0

Uma solução atualizada que fornece uma lista:

dataFrame.select("YOUR_COLUMN_NAME").map(r => r.getString(0)).collect.toList
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.