数据框空值在 UDF 之后转换为 0。为啥?

Posted

技术标签:

【中文标题】数据框空值在 UDF 之后转换为 0。为啥?【英文标题】:Dataframe null values transformed to 0 after UDF. Why?数据框空值在 UDF 之后转换为 0。为什么? 【发布时间】:2018-09-19 06:30:00 【问题描述】:

访问数据框Row 值时如何处理空值?空指针异常真的需要手动处理吗?一定有更好的解决方案。

case class FirstThing(id:Int, thing:String, other:Option[Double])

val df = Seq(FirstThing(1, "first", None), FirstThing(1, "second", Some(2)), FirstThing(1, "third", Some(3))).toDS
df.show

val list = df.groupBy("id").agg(collect_list(struct("thing", "other")).alias("mylist"))
list.show(false)

NPE 失败:

val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getDouble(1)))
list.withColumn("aa", xxxx(col("mylist"))).show(false)

这奇怪地给出了 0:

val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getAs[Double]("other")))
list.withColumn("aa", xxxx(col("mylist"))).show(false)

+---+-----------------------------------------+---------------+
|id |mylist                                   |aa             |
+---+-----------------------------------------+---------------+
|1  |[[first,null], [second,2.0], [third,3.0]]|[0.0, 2.0, 3.0]|
+---+-----------------------------------------+---------------+

遗憾的是,这种适用于数据帧/数据集的方法也失败了:

val xxxx = udf((t:Seq[Row])=> t.map(elem => elem.getAs[Option[Double]]("other")))
list.withColumn("aa", xxxx(col("mylist"))).show(false)

ClassCastException: java.lang.Double 不能转换为 scala.Option

【问题讨论】:

【参考方案1】:

使用getAs[Double] 并将其包装在Option 中会得到预期的结果:

val xxxx = udf((t: Seq[Row])=> t.map(elem => Option(elem.getAs[Double]("other"))))
list.withColumn("aa", xxxx($"mylist")).show(false)

+---+-----------------------------------------+----------------+
|id |mylist                                   |aa              |
+---+-----------------------------------------+----------------+
|1  |[[first,null], [second,2.0], [third,3.0]]|[null, 2.0, 3.0]|
+---+-----------------------------------------+----------------+

getAs[Option[Double]] 不起作用的原因可能是数据框架构没有保留该列具有选项的知识。 udf 之前的架构:

root
 |-- id: integer (nullable = false)
 |-- mylist: array (nullable = true)
 |    |-- element: struct (containsNull = true)
 |    |    |-- thing: string (nullable = true)
 |    |    |-- other: double (nullable = true)

【讨论】:

以上是关于数据框空值在 UDF 之后转换为 0。为啥?的主要内容,如果未能解决你的问题,请参考以下文章

antdesign选择框空值没有提示

casewhen嵌套casewhen出现空值为啥会出现空值

EXCEL这列中的空单元格为啥选“空值”定位不了?

Spark UDF 检索最后一个非空值

怎么设置access查询中空值为0?

将 0 和 1 (float64) 转换为布尔值时将空值转换为 True [重复]