Extraire les valeurs de colonne de Dataframe en tant que liste dans Apache Spark
Je voudrais convertir une colonne de chaîne d'un dataframe en une liste. Ce que je peux trouver à partir de l'API Dataframe
est RDD, j'ai donc essayé de le convertir en RDD en premier, puis d'appliquer la fonction toArray
au RDD. Dans ce cas, la longueur et le SQL fonctionnent très bien. Cependant, le résultat que J'ai obtenu de RDD a des crochets autour de chaque élément comme celui-ci [A00001]
. Je me demandais s'il y avait un moyen approprié de convertir une colonne en une liste ou un moyen de supprimer les crochets.
Toutes les suggestions seraient apprécier. Merci!!!!
5 réponses
Cela devrait renvoyer la collection contenant une seule liste:
dataFrame.select("YOUR_COLUMN_NAME").rdd.map(r => r(0)).collect()
Sans le mappage, vous obtenez simplement un objet Row, qui contient chaque colonne de la base de données.
Gardez à l'esprit que cela vous donnera probablement une liste de tout type. Ïsi vous voulez spécifier le type de résultat, vous pouvez utiliser .asInstanceOf[YOUR_TYPE] dans r => r(0).asInstanceOf[YOUR_TYPE]
mapping
P.S. en raison de la conversion automatique, vous pouvez ignorer la partie .rdd
.
Avec Spark 2.x et Scala 2.11
Je pense à 3 façons possibles de convertir les valeurs d'une colonne spécifique en List
Extraits de code communs pour toutes les approches
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")
Approche 1
df.select("id").collect().map(_(0)).toList
// res9: List[Any] = List(one, two, three)
Que se passe-t-il maintenant? Nous collectons des données au pilote avec collect()
et sélectionnons l'élément zéro de chaque enregistrement.
cela ne pourrait pas être une excellente façon de le faire, améliorons-le avec la prochaine approche.
Approche 2
df.select("id").rdd.map(r => r(0)).collect.toList
//res10: List[Any] = List(one, two, three)
Comment est-ce mieux? Nous avons distribué la charge de transformation de carte entre les travailleurs plutôt que le conducteur unique.
je sais rdd.map(r => r(0))
ne semble pas élégant vous. Alors, abordons-le dans la prochaine approche.
Approche 3
df.select("id").map(r => r.getString(0)).collect.toList
//res11: List[String] = List(one, two, three)
Ici, nous ne convertissons pas DataFrame en RDD. Regardez map
il n'acceptera pas r => r(0)
(ou _(0)
) comme approche précédente en raison de problèmes d'encodeur dans DataFrame. Donc, finissez par utiliser r => r.getString(0)
et il serait abordé dans next versions de Spark.
Conclusion
Toutes les options donnent la même sortie mais 2 et 3 sont efficaces, enfin la 3ème est efficace et élégante (je pense).
Databricks cahier de liaison qui sera disponible jusqu'à 6 mois à partir de 2017/05/20
Je sais que la réponse donnée et demandée est supposée pour Scala, donc je fournis juste un petit extrait de code Python au cas où un utilisateur de PySpark serait curieux. La syntaxe est similaire à la réponse donnée, mais pour faire apparaître correctement la liste, je dois référencer le nom de la colonne une deuxième fois dans la fonction de mappage et je n'ai pas besoin de l'instruction select.
C'est-à-dire un DataFrame contenant une colonne nommée " Raw "
Pour obtenir chaque valeur de ligne dans" Raw " combiné comme une liste où chaque entrée est une valeur de ligne de " Raw " j'utilise simplement:
MyDataFrame.rdd.map(lambda x: x.Raw).collect()
Dans Scala et Spark 2+, Essayez ceci (en supposant que le nom de votre colonne est " s"):
df.select('s).as[String].collect
sqlContext.sql(" select filename from tempTable").rdd.map(r => r(0)).collect.toList.foreach(out_streamfn.println) //remove brackets
Cela fonctionne parfaitement