我想更改数据框 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的解决方案。
答案 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)