我有一个数据框,其中一个列的值为空。
我将列传递给udf以进行数学乘法。我想跳过该udf为空值。我不想使用na.fill替换为空。
DF的架构如下所示 DataFrame1
root
|-- Name: string (nullable =true)
|-- Value: decimal(38,0) (nullable=true) //This is the col
|-- powValue: integer (nullable=true)
|-- mulValue: integer (nullable=true)
def udfFn(val1: Integer, powVal:Integer, mulVal:Integer) = {
val bd1 = new BigDecimal(val1);
val bd2 =bd1.scakeByPowerTen(-powVal)
val bd3 = new BigDecimal(mulVal)
val bd4=bd2.multiply(bd3)
}
val calUDF=udf({(val1: Integer, powVal:Integer, mulVal:Integer)=>
udfFn(val1,powVal,mulVal)})
val newDf=DataFrame1.withColumn("Final_Value",calUDF(col("Value"),col("powValue"),col("mulValue")))
我的 DataFrame1 在值
列中可以包含0个空数字。答案 0 :(得分:0)
基于类型val1
,看来Value
和BigDecimal
实际上应该是decimal(38,0)
,所以我将在下面的代码中进行假设。
执行此操作的快速方法只是使用一个好的'ole if-else
语句。这可能也是最有效的方式,具体取决于:
def udfFn(val1: BigDecimal, powVal: Int, mulVal: Int): BigDecimal =
if (val1 != null && powVal != null && mulVal != null) {
val mul = new BigDecimal(mulVal)
val1.scaleByPowerTen(-powVal).multiply(mul)
} else {
null
}
我认为这看起来有点丑陋,如果您想使其更好地阅读,这是函数编程的工作! Option
和for
的救援知识! (请注意,如果性能是一个问题,那么第一个解决方案可能是您的最佳选择)
您可以执行以下操作:
def udfFn(val1: BigDecimal, powVal: Int, mulVal: Int): Option[BigDecimal] =
val r = for {
bd1 <- Option(val1)
pow <- Option(powVal)
mul <- Option(mulVal).map(new BigDecimal(_))
} yield (bd1.scaleByPowerTen(-pow).multiply(mul))
仅当每个输入for
为Option
时,对Some
的理解将产生Option
的{{1}},否则为Some
。
我个人更喜欢使用None
而不是Dataset
来完成此操作,因为我认为它使转换更易于理解,并且使每个步骤的架构都非常明确,并且允许您在不依赖UDF的情况下编写转换,但是绝对最好做您和/或组织更满意的事情。对于DataFrame
解决方案,我将创建几个案例类:
Dataset
然后执行转换的代码将是这样:
case class NewData(name: Option[String], val1: Option[BigDecimal], powVal: Option[Int], mulVal: Option[Int], finalValue: Option[BigDecimal])
case class SomeData(name: Option[String], val1: Option[BigDecimal], powVal: Option[Int], mulVal: Option[Int]) {
def toNewData: NewData = {
val fv = for {
bd1 <- val1
pow <- powVal
mul <- mulVal.map(new BigDecimal(_))
} yield (bd1.scaleByPowerTen(-pow).multiply(mul))
NewData(name, val1, powVal, mulVal, fv)
}
}