Spark Scala按一些值范围拆分DataFrame

时间:2017-05-29 02:58:02

标签: scala apache-spark spark-dataframe apache-spark-mllib

假设我的数据框中包含名为x的列,其值范围为[0, 1]。我希望将x列的值除以[0, 0.1)[0.1, 0.2) ... [0.9, 1]等范围。有没有一个好的,快速的方法呢?我在Scala中使用Spark 2。

更新:理想情况下,应该有10个新数据帧包含每个范围的数据。

2 个答案:

答案 0 :(得分:0)

如果您打算对双类型列进行离散化,则可能只需执行此操作(将列乘以10然后将其转换为整数类型,该列将被切割为10个离散的列):

import org.apache.spark.sql.types.IntegerType

val df = Seq(0.32, 0.5, 0.99, 0.72, 0.11, 0.03).toDF("A")
// df: org.apache.spark.sql.DataFrame = [A: double]

df.withColumn("new", ($"A" * 10).cast(IntegerType)).show
+----+---+
|   A|new|
+----+---+
|0.32|  3|
| 0.5|  5|
|0.99|  9|
|0.72|  7|
|0.11|  1|
|0.03|  0|
+----+---+

答案 1 :(得分:0)

扩展@ Psidom创建范围的解决方案,这是为每个范围创建数据框的一种方法:

import org.apache.spark.sql.types.IntegerType
val df = Seq(0.2, 0.71, 0.95, 0.33, 0.28, 0.8, 0.73).toDF("x")
val df2 = df.withColumn("g", ($"x" * 10.0).cast(IntegerType))

df2.show
+----+---+
|   x|  g|
+----+---+
| 0.2|  2|
|0.71|  7|
|0.95|  9|
|0.33|  3|
|0.28|  2|
| 0.8|  8|
|0.73|  7|
+----+---+

val dfMap = df2.select($"g").distinct.
  collect.
  flatMap(_.toSeq).
  map( g => g -> df2.where($"g" === g) ).
  toMap

dfMap.getOrElse(3, null).show
+----+---+
|   x|  g|
+----+---+
|0.33|  3|
+----+---+

dfMap.getOrElse(7, null).show
+----+---+
|   x|  g|
+----+---+
|0.71|  7|
|0.73|  7|
+----+---+

[UPDATE]

如果范围不规则,您可以定义一个函数,将Double映射到相应的Int范围id,然后用UDF包装,如下所示:

val g: Double => Int = x => x match {
  case x if (x >= 0.0 && x < 0.12345) => 1
  case x if (x >= 0.12345 && x < 0.4834) => 2
  case x if (x >= 0.4834 && x < 1.0) => 3
  case _ => 99  // catch-all
}

val groupUDF = udf(g)

val df = Seq(0.1, 0.2, 0.71, 0.95, 0.03, 0.09, 0.44, 5.0).toDF("x")
val df2 = df.withColumn("g", groupUDF($"x"))

df2.show
+----+---+
|   x|  g|
+----+---+
| 0.1|  1|
| 0.2|  2|
|0.71|  3|
|0.95|  3|
|0.03|  1|
|0.09|  1|
|0.44|  2|
| 5.0| 99|
+----+---+