web-dev-qa-db-fra.com

Scala ajoute une nouvelle colonne à dataframe par expression

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.

11
Robin Wang

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|
+---+---+---+
12
Raphael Roth

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|
+-----+---+---+---+--------------------+
5
rajesh

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.

1
Vidura Mudalige