Je vais ajouter une nouvelle colonne à une image de données avec l'expression . Par exemple, j'ai une image de données de
+-----+----------+----------+-----+
| C1 | C2 | C3 |C4 |
+-----+----------+----------+-----+
|steak|1 |1 | 150|
|steak|2 |2 | 180|
| fish|3 |3 | 100|
+-----+----------+----------+-----+
et je veux créer une nouvelle colonne C5 avec l'expression "C2/C3 + C4", en supposant qu'il y ait plusieurs nouvelles colonnes à ajouter, et que les expressions peuvent être différentes et provenir de la base de données.
Y at-il un bon moyen de le faire?
Je sais que si j'ai une expression du type "2 + 3 * 4", je peux utiliser scala.tools.reflect.ToolBox pour l’évaluer.
Et normalement j'utilise df.withColumn pour ajouter une nouvelle colonne.
Il me semble que je dois créer un fichier UDF, mais comment puis-je transmettre la valeur des colonnes en tant que paramètres à UDF? en particulier il peut y avoir plusieurs expressions besoin de calculer différentes colonnes.
Cela peut être fait en utilisant expr
pour créer un Column
à partir d'une expression:
val df = Seq((1,2)).toDF("x","y")
val myExpression = "x+y"
import org.Apache.spark.sql.functions.expr
df.withColumn("z",expr(myExpression)).show()
+---+---+---+
| x| y| z|
+---+---+---+
| 1| 2| 3|
+---+---+---+
Deux approches:
import spark.implicits._ //so that you could use .toDF
val df = Seq(
("steak", 1, 1, 150),
("steak", 2, 2, 180),
("fish", 3, 3, 100)
).toDF("C1", "C2", "C3", "C4")
import org.Apache.spark.sql.functions._
// 1st approach using expr
df.withColumn("C5", expr("C2/(C3 + C4)")).show()
// 2nd approach using selectExpr
df.selectExpr("*", "(C2/(C3 + C4)) as C5").show()
+-----+---+---+---+--------------------+
| C1| C2| C3| C4| C5|
+-----+---+---+---+--------------------+
|steak| 1| 1|150|0.006622516556291391|
|steak| 2| 2|180| 0.01098901098901099|
| fish| 3| 3|100| 0.02912621359223301|
+-----+---+---+---+--------------------+
Dans Spark 2.x, vous pouvez créer une nouvelle colonne C5 avec l'expression "C2/C3 + C4" à l'aide de withColumn()
et org.Apache.spark.sql.functions._
.
val currentDf = Seq(
("steak", 1, 1, 150),
("steak", 2, 2, 180),
("fish", 3, 3, 100)
).toDF("C1", "C2", "C3", "C4")
val requiredDf = currentDf
.withColumn("C5", (col("C2")/col("C3")+col("C4")))
Vous pouvez également faire de même en utilisant org.Apache.spark.sql.Column
également ..__ (mais la complexité de l'espace est légèrement plus élevée dans cette approche que d'utiliser org.Apache.spark.sql.functions._
en raison de la création d'objet Column).
val requiredDf = currentDf
.withColumn("C5", (new Column("C2")/new Column("C3")+new Column("C4")))
Cela a parfaitement fonctionné pour moi. J'utilise Spark 2.0.2.