web-dev-qa-db-fra.com

Ajouter une colonne au cadre de données dans Apache Spark 1.3

Est-il possible et quelle serait la méthode la plus efficace pour ajouter une colonne à Data Frame?

Plus spécifiquement, la colonne peut servir d'identifiant de ligne pour le cadre de données existant.

Dans un cas simplifié, lire à partir d'un fichier et ne pas le marquer, je peux penser à quelque chose comme ci-dessous (en Scala), mais cela se termine par des erreurs (à la ligne 3), et de toute façon cela ne ressemble pas au meilleur chemin possible:

var dataDF = sc.textFile("path/file").toDF() 
val rowDF = sc.parallelize(1 to DataDF.count().toInt).toDF("ID") 
dataDF = dataDF.withColumn("ID", rowDF("ID")) 
51
Oleg Shirokikh

Cela fait un moment que j'ai posté la question et il semble que d'autres personnes aimeraient aussi obtenir une réponse. Voici ce que j'ai trouvé.

La tâche initiale consistait donc à ajouter une colonne avec des identificateurs de ligne (en gros, une séquence 1 to numRows) à un cadre de données donné, afin que l’ordre/la présence des lignes puisse être suivi (par exemple, lors de l’échantillonnage). Ceci peut être réalisé par quelque chose dans ce sens:

sqlContext.textFile(file).
zipWithIndex().
map(case(d, i)=>i.toString + delimiter + d).
map(_.split(delimiter)).
map(s=>Row.fromSeq(s.toSeq))

En ce qui concerne le cas général de l'ajout d'une colonne à un bloc de données:

Les "plus proches" de cette fonctionnalité dans Spark sont withColumn et withColumnRenamed. Selon Scala docs , l'ancien Retourne un nouveau DataFrame en ajoutant une colonne. À mon avis, cette définition est un peu déroutante et incomplète. Ces deux fonctions ne peuvent fonctionner que sur la trame de données this, c’est-à-dire avec deux trames de données df1 et df2 avec la colonne col:

val df = df1.withColumn("newCol", df1("col") + 1) // -- OK
val df = df1.withColumn("newCol", df2("col") + 1) // -- FAIL

Ainsi, à moins que vous ne parveniez à transformer une colonne dans un cadre de données existant en la forme dont vous avez besoin, vous ne pouvez pas utiliser withColumn ou withColumnRenamed pour ajouter des colonnes arbitraires (cadres de données autonomes ou autres).

Comme indiqué ci-dessus, la solution de contournement consiste peut-être à utiliser un join, ce qui serait assez compliqué, bien que possible. Vous pouvez associer les clés uniques comme ci-dessus avec zipWithIndex travail. Bien que l'efficacité soit ...

Il est clair que l'ajout d'une colonne au bloc de données n'est pas une fonctionnalité facile pour un environnement distribué et il peut ne pas y avoir de méthode très efficace et soignée pour cela. Mais je pense qu'il est toujours très important de disposer de cette fonctionnalité essentielle, même avec des avertissements de performance.

51
Oleg Shirokikh

pas sûr si cela fonctionne dans spark 1.3 mais dans spark 1.5 J'utilise withColumn:

import sqlContext.implicits._
import org.Apache.spark.sql.functions._


df.withColumn("newName",lit("newValue"))

J'utilise ceci lorsque j'ai besoin d'utiliser une valeur qui n'est pas liée aux colonnes existantes de la base de données

Ceci est similaire à la réponse de @ NehaM mais plus simple

29
Tal Joffe

J'ai pris l'aide de la réponse ci-dessus. Cependant, je le trouve incomplet si nous voulons changer un DataFrame et que les API actuelles sont légèrement différentes dans Spark 1.6. zipWithIndex() renvoie un Tuple de (Row, Long) qui contient chaque ligne et l'index correspondant. Nous pouvons l'utiliser pour créer de nouveaux Row selon nos besoins.

val rdd = df.rdd.zipWithIndex()
             .map(indexedRow => Row.fromSeq(indexedRow._2.toString +: indexedRow._1.toSeq))
val newstructure = StructType(Seq(StructField("Row number", StringType, true)).++(df.schema.fields))
sqlContext.createDataFrame(rdd, newstructure ).show

J'espère que cela vous sera utile.

6
NehaM

Vous pouvez utiliser row_number avec fonction Window comme ci-dessous pour obtenir l'identifiant distinct de chaque ligne d'un cadre de données.

df.withColumn("ID", row_number() over Window.orderBy("any column name in the dataframe"))

Vous pouvez aussi utiliser monotonically_increasing_id pour le même que

df.withColumn("ID", monotonically_increasing_id())

Et il y a quelques autres moyens aussi.

3
Ramesh Maharjan