Estrai i valori delle colonne di Dataframe come elenco in Apache Spark


87

Voglio convertire una colonna di stringhe di un data frame in un elenco. Quello che posso trovare Dataframedall'API è RDD, quindi ho provato prima a riconvertirlo in RDD, quindi applicare la toArrayfunzione all'RDD. In questo caso, la lunghezza e l'SQL funzionano perfettamente. Tuttavia, il risultato che ho ottenuto da RDD ha parentesi quadre attorno a ogni elemento come questo [A00001]. Mi chiedevo se esiste un modo appropriato per convertire una colonna in un elenco o un modo per rimuovere le parentesi quadre.

Tutti i suggerimenti sarebbero apprezzati. Grazie!


Risposte:


117

Questo dovrebbe restituire la raccolta contenente l'elenco singolo:

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

Senza la mappatura, ottieni solo un oggetto Row, che contiene ogni colonna del database.

Tieni presente che questo probabilmente ti farà ottenere un elenco di Qualsiasi tipo. ÏSe desideri specificare il tipo di risultato, puoi utilizzare .asInstanceOf [YOUR_TYPE] nella r => r(0).asInstanceOf[YOUR_TYPE]mappatura

PS grazie alla conversione automatica puoi saltare la .rddparte.


3
Per qualche strana ragione funziona al contrario (Spark 2.1.0) collect().map(r => r(0)): questo ordine presenta degli svantaggi?
Boern

1
Può essere più lento: la tua soluzione raccoglie prima tutti i dati sul driver, dopodiché esegue la mappatura sul driver (senza l'ausilio di esecutori), utilizzando solo la potenza di elaborazione del singolo driver.
TheMP

73

Con Spark 2.xe Scala 2.11

Penserei a 3 possibili modi per convertire i valori di una colonna specifica in List.

Frammenti di codice comuni per tutti gli approcci

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

Approccio 1

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

Che succede ora? Stiamo raccogliendo dati a Driver con collect()e selezionando l'elemento zero da ogni record.

Questo non potrebbe essere un modo eccellente per farlo, miglioriamolo con il prossimo approccio.


Approccio 2

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

Come è meglio? Abbiamo distribuito il carico di trasformazione della mappa tra i lavoratori anziché il singolo Driver.

Lo so che rdd.map(r => r(0))non ti sembra elegante. Quindi, affrontiamolo nel prossimo approccio.


Approccio 3

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

Qui non stiamo convertendo DataFrame in RDD. Guarda mapche non accetterà r => r(0)(o _(0)) come l'approccio precedente a causa di problemi del codificatore in DataFrame. Quindi finisci per usare r => r.getString(0)e verrebbe affrontato nelle prossime versioni di Spark.

Conclusione

Tutte le opzioni danno lo stesso output ma 2 e 3 sono efficaci, infine la terza è efficace ed elegante (penso).

Taccuino di Databricks


24

So che la risposta data e richiesta si presume per Scala, quindi sto solo fornendo un piccolo frammento di codice Python nel caso in cui un utente PySpark sia curioso. La sintassi è simile alla risposta data, ma per far apparire correttamente l'elenco devo fare riferimento al nome della colonna una seconda volta nella funzione di mappatura e non ho bisogno dell'istruzione select.

cioè un DataFrame, contenente una colonna denominata "Raw"

Per ottenere ogni valore di riga in "Raw" combinato come un elenco in cui ogni voce è un valore di riga da "Raw", utilizzo semplicemente:

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

4
Questo fornisce un elenco di oggetti Row. E se volessi un elenco dei valori?
ThatDataGuy

Questo fornisce un elenco di valori.
abby sobh

Grazie per aver condiviso questo! Questo funziona alla grande per me, chiedendomi se c'è un modo per accelerare, funziona piuttosto lentamente
Mojgan Mazouchi

5

In Scala e Spark 2+, prova questo (supponendo che il nome della tua colonna sia "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

funziona perfettamente


2
from pyspark.sql.functions import col

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

qui collect è funzioni che a loro volta lo convertono in list. Stai attento a usare l'elenco sull'enorme set di dati. Ridurrà le prestazioni. È bene controllare i dati.


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

Dato che nessuno ha fornito alcuna soluzione in java (Real Programming Language) può ringraziarmi più tardi


0

Una soluzione aggiornata che ti fornisce un elenco:

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

-1

Questa è la risposta di Java.

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.