Spark根据现有列的映射值创建新列

NateH06

我正在尝试将数据框中的一列的值映射到新值,并使用UDF将其放入新列中,但是我无法使UDF接受也不是列的参数。例如,我有一个dfOriginial这样的数据框

+-----------+-----+
|high_scores|count|
+-----------+-----+
|          9|    1|
|         21|    2|
|         23|    3|
|          7|    6|
+-----------+-----+

而且我正试图了解数值所属的bin,因此我可以像这样构造一个bin列表:

case class Bin(binMax:BigDecimal, binWidth:BigDecimal) {
    val binMin = binMax - binWidth

    // only one of the two evaluations can include an  "or=", otherwise a value could fit in 2 bins
    def fitsInBin(value: BigDecimal): Boolean = value > binMin && value <= binMax

    def rangeAsString(): String = {
        val sb = new StringBuilder()
        sb.append(trimDecimal(binMin)).append(" - ").append(trimDecimal(binMax))
        sb.toString()
    }
}

然后我想像这样转换我的旧数据框,使其dfBin

+-----------+-----+---------+
|high_scores|count|bin_range|
+-----------+-----+---------+
|          9|    1| 0 - 10  |
|         21|    2| 20 - 30 |
|         23|    3| 20 - 30 |
|          7|    6| 0 - 10  |
+-----------+-----+---------+

这样我最终可以通过调用来获取垃圾箱实例的数量.groupBy("bin_range").count()

我正在尝试dfBin通过将withColumn函数与UDF一起使用来生成

这是我尝试使用的UDF的代码:

val convertValueToBinRangeUDF = udf((value:String, binList:List[Bin]) => {
    val number = BigDecimal(value)
    val bin = binList.find( bin => bin.fitsInBin(number)).getOrElse(Bin(BigDecimal(0), BigDecimal(0)))
    bin.rangeAsString()
})

val binList = List(Bin(10, 10), Bin(20, 10), Bin(30, 10), Bin(40, 10), Bin(50, 10))

val dfBin = dfOriginal.withColumn("bin_range", convertValueToBinRangeUDF(col("high_scores"), binList))

但这给了我一个类型不匹配:

Error:type mismatch;
 found   : List[Bin]
 required: org.apache.spark.sql.Column
        val valueCountsWithBin = valuesCounts.withColumn(binRangeCol, convertValueToBinRangeUDF(col(columnName), binList))

看到UDF的定义,我认为它应该可以很好地处理转换,但是显然没有任何想法吗?

ido堂

问题在于,的参数UDF都应为列类型。一种解决方案是将其转换binList为列并将其传递给UDF类似于当前代码的列。

但是,UDF稍微调整一下并将其变成会更简单def通过这种方式,您可以轻松地传递其他非列类型的数据:

def convertValueToBinRangeUDF(binList: List[Bin]) = udf((value:String) => {
  val number = BigDecimal(value)
  val bin = binList.find( bin => bin.fitsInBin(number)).getOrElse(Bin(BigDecimal(0), BigDecimal(0)))
  bin.rangeAsString()
})

用法:

val dfBin = valuesCounts.withColumn("bin_range", convertValueToBinRangeUDF(binList)($"columnName"))

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章