Scala通过表达式向数据框添加新列

时间:2017-09-07 03:39:24

标签: scala apache-spark dataframe

我将使用表达式向数据框添加新列。 例如,我的数据框为

+-----+----------+----------+-----+
| C1  | C2       |   C3     |C4   |
+-----+----------+----------+-----+
|steak|1         |1         |  150|
|steak|2         |2         |  180|
| fish|3         |3         |  100|
+-----+----------+----------+-----+

我想创建一个带有表达式" C2 / C3 + C4"的新列C5,假设有几个新列需要添加,表达式可能不同,来自数据库。

有没有好办法呢?

我知道如果我有一个像" 2 + 3 * 4"我可以使用scala.tools.reflect.ToolBox来评估它。

通常我使用df.withColumn添加新列。

似乎我需要创建一个UDF,但是如何将columns值作为参数传递给UDF?特别是可能有多个表达式需要不同的列计算。

3 个答案:

答案 0 :(得分:15)

可以使用expr从表达式创建Column来完成此操作:

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

答案 1 :(得分:5)

两种方法:

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

答案 2 :(得分:2)

在Spark 2.x中,您可以创建一个新的列C5,其表达式为" C2 / C3 + C4"使用withColumn()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")))

此外,您也可以使用org.apache.spark.sql.Column执行相同操作。 (但由于创建了Column对象,这种方法的空间复杂度比使用org.apache.spark.sql.functions._高一些)

 val requiredDf = currentDf
                   .withColumn("C5", (new Column("C2")/new Column("C3")+new Column("C4")))

这对我来说非常合适。我使用的是Spark 2.0.2。