在Scala中用很多列转换数据框行

时间:2019-02-07 22:43:14

标签: java scala apache-spark dataframe apache-spark-sql

我想更改数据框 df 的一行中多个字段的值。通常,我会使用地图进行逐行转换。像这样:

  + --- + --------- +
| num |名称|
+ --- + --------- +
| 1 |氢|
| 2 |氦气|
+ --- + --------- +
df.map(row => {
      val名称= row.getAs(“名称”).toString.toUpperCase
      (行(0),名称)
    })
 

但是现在我有一个数据框,它具有许多列的精心设计的架构,从中我只想更改某些列的值。一列值的变化取决于其他列。如何避免在元组中写入所有列值(例如 row.get(0),row.get(1)... row.get(30)),而只写那些已经变化?考虑具有以下架构的 df

 案例类DFSchema(id:字符串,名称:字符串,map1:Map [String,String],...,map30 [Sting,String])
 

仅当 id 为时,我想更新 df.select(“ map30”)的键和值并修改“ name” “城市” 。当然,其他列(在模式中表示为 mapX

我没有考虑将UDF用于此问题,即使UDF返回多列结构,我也不知道如何使用 withColumn()更改多列,因为它仅接受“一个” ”列名称。但是,与在行上使用 .map 一样,也欢迎使用UDF的解决方案。

2 个答案:

答案 0 :(得分:2)

您可以尝试以下操作:

val rules = Seq(
  "columnA" -> lit(20),
  "columnB" -> col("columnB").plus(col("columnC")),
  "columnC" -> col("columnC").minus(col("columnD")),
  "columnN" -> col("columnA").plus(col("columnB")).plus(col("columnC"))
)

def (inputDf: DataFrame): DataFrame = {
  rules.foldLeft(inputDf) {
    case (df, (columnName, ruleColumn)) => df.withColumn(columnName, ruleColumn)
  }
}

这里有rules,它是成对的序列,其中第一个值是我们要更改/添加的目标列的名称,第二个是应使用从属列应用的规则。 / p>

使用foldLeft操作,我们将所有规则应用于输入DataFrame

答案 1 :(得分:2)

您可以尝试以下方法:

   df.show(false)

    val newColumns = df.columns.map { x =>
      if (x == "name") {
        when(col("id") === "city", lit("miami")).otherwise(col("name")).as("name")
      } else if (x == "map30") {
        when(col("id") === "city", map(lit("h"), lit("update"), lit("n"), lit("new"))).otherwise(col("map30")).as("map30")
      } else {
        col(x).as(x)
      }
    }

    val cleanDf = df.select(newColumns: _*)

    cleanDf.show(false)