Extraiga los valores de columna de Dataframe como lista en Apache Spark

86

Quiero convertir una columna de cadena de un marco de datos en una lista. Lo que puedo encontrar en la DataframeAPI es RDD, así que primero intenté convertirlo a RDD y luego apliqué la toArrayfunción al RDD. En este caso, la longitud y SQL funcionan bien. Sin embargo, el resultado que obtuve de RDD tiene corchetes alrededor de cada elemento como este [A00001]. Me preguntaba si hay una forma adecuada de convertir una columna en una lista o una forma de eliminar los corchetes.

Cualquier sugerencia sera apreciada. ¡Gracias!

SH Y.
fuente

Respuestas:

117

Esto debería devolver la colección que contiene una lista única:

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

Sin la asignación, solo obtiene un objeto Row, que contiene todas las columnas de la base de datos.

Tenga en cuenta que esto probablemente le dará una lista de cualquier tipo. Ïsi desea especificar el tipo de resultado, puede usar .asInstanceOf [YOUR_TYPE] en la r => r(0).asInstanceOf[YOUR_TYPE]asignación

PD: debido a la conversión automática, puede omitir la .rddparte.

Niemand
fuente
3
Por alguna extraña razón, funciona al revés (Spark 2.1.0) collect().map(r => r(0)): ¿este orden tiene alguna desventaja?
Boern
Puede ser más lento: su solución primero recopila todos los datos en el controlador y luego realiza la asignación en el controlador (sin la ayuda de los ejecutores), utilizando solo la potencia de procesamiento de un solo controlador.
Niemand
72

Con Spark 2.xy Scala 2.11

Pensaría en 3 formas posibles de convertir valores de una columna específica en List.

Fragmentos de código comunes para todos los enfoques

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

Enfoque 1

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

¿Que pasa ahora? Estamos recopilando datos para Driver collect()y seleccionando el elemento cero de cada registro.

Esta no podría ser una excelente manera de hacerlo, mejorémosla con el siguiente enfoque.


Enfoque 2

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

¿Cómo es mejor? Hemos distribuido la carga de transformación de mapas entre los trabajadores en lugar de un solo controlador.

Sé que rdd.map(r => r(0))no te parece elegante. Entonces, abordemos esto en el siguiente enfoque.


Enfoque 3

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

Aquí no estamos convirtiendo DataFrame a RDD. Mire mapque no aceptará r => r(0)(o _(0)) como el enfoque anterior debido a problemas del codificador en DataFrame. Así que termine usándolo r => r.getString(0)y se abordará en las próximas versiones de Spark.

Conclusión

Todas las opciones dan el mismo resultado, pero 2 y 3 son efectivas, finalmente la tercera es efectiva y elegante (creo).

Cuaderno de Databricks

mrsrinivas
fuente
24

Sé que la respuesta dada y solicitada se asume para Scala, por lo que solo estoy proporcionando un pequeño fragmento de código Python en caso de que un usuario de PySpark tenga curiosidad. La sintaxis es similar a la respuesta dada, pero para sacar la lista correctamente, en realidad tengo que hacer referencia al nombre de la columna por segunda vez en la función de mapeo y no necesito la declaración de selección.

es decir, un DataFrame, que contiene una columna denominada "Raw"

Para obtener cada valor de fila en "Raw" combinado como una lista donde cada entrada es un valor de fila de "Raw", simplemente uso:

MyDataFrame.rdd.map(lambda x: x.Raw).collect()
abby sollozo
fuente
4
Esto da una lista de objetos Row. ¿Qué pasa si quieres una lista de los valores?
ThatDataGuy
Esto da una lista de valores.
abby sobh
¡Gracias por compartir esto! Esto funciona muy bien para mí, solo me pregunto si hay una manera de acelerar esto, funciona bastante lento
Mojgan Mazouchi
5

En Scala y Spark 2+, intente esto (asumiendo que el nombre de su columna es "s"): df.select('s).as[String].collect

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

funciona perfectamente

Shaina Raza
fuente
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

Como nadie ha dado ninguna solución en java (Real Programming Language), puede agradecerme más tarde

usuario12910640
fuente
0
from pyspark.sql.functions import col

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

aquí se recopilan funciones que a su vez lo convierten en lista. Tenga cuidado de utilizar la lista en el enorme conjunto de datos. Disminuirá el rendimiento. Es bueno verificar los datos.

grano de amarnath
fuente
0

Esta es la respuesta de Java.

df.select("id").collectAsList();
vahbuna
fuente
0

Una solución actualizada que le ofrece una lista:

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