Spark 1.6,DataFrame:通过添加行来填补空白

时间:2016-02-17 17:49:26

标签: apache-spark dataframe apache-spark-sql

我有一个如下所示的DataFrame:

+-----+---+-----+
|  id |ind| freq|
+-----+---+-----+
|user1|  1|    5|
|user2|  0|   13|
|user2|  2|    4|
|user3|  2|    7|
|user3|  3|   45|
+-----+---+-----+

ind的整数值介于0和3之间。

我想为每个用户添加缺少的ind值,同时使用默认值(如0)填充freq列,因此输出DataFrame如下所示:

+-----+---+-----+
|  id |ind| freq|
+-----+---+-----+
|user1|  0|    0|
|user1|  1|    5|
|user1|  2|    0|
|user1|  3|    0|
|user2|  0|   13|
|user2|  1|    0|
|user2|  2|    4|
|user2|  3|    0|
|user3|  0|    0|
|user3|  1|    0|
|user3|  2|    7|
|user3|  3|   45|
+-----+---+-----+

最有效的方法是什么?

2 个答案:

答案 0 :(得分:3)

这不是最好的解决方案,但从我的头脑中,它将完成这项工作:

import org.apache.spark.sql.Row


val df = sc.parallelize(List(("user1",1,5),("user2",  0,   13),("user2",  2,   4),("user3",  2,    7),("user3",  3,   45))).toDF("id","ind","freq")
df.show

// +-----+---+----+
// |   id|ind|freq|
// +-----+---+----+
// |user1|  1|   5|
// |user2|  0|  13|
// |user2|  2|   4|
// |user3|  2|   7|
// |user3|  3|  45|
// +-----+---+----+

val df2 = df.groupBy('id).pivot("ind").max("freq").na.fill(0)
df2.show

// +-----+---+---+---+---+
// |   id|  0|  1|  2|  3|
// +-----+---+---+---+---+
// |user1|  0|  5|  0|  0|
// |user2| 13|  0|  4|  0|
// |user3|  0|  0|  7| 45|
// +-----+---+---+---+---+

val cols = df2.columns

val df3 = df2.rdd.map {
  case r : Row =>
    val id = r.getAs[String]("id")
    cols.map(ind => (id,ind,r.getAs[Integer](ind)))
}.flatMap(_.toSeq).filter(_._2 != "id").toDF("id","ind","freq")

df3.show

// +-----+---+----+
// |   id|ind|freq|
// +-----+---+----+
// |user1|  0|   0|
// |user1|  1|   5|
// |user1|  2|   0|
// |user1|  3|   0|
// |user2|  0|  13|
// |user2|  1|   0|
// |user2|  2|   4|
// |user2|  3|   0|
// |user3|  0|   0|
// |user3|  1|   0|
// |user3|  2|   7|
// |user3|  3|  45|
// +-----+---+----+

我使用pivot中的GroupeData函数,然后按列展平它。 (Spark 1.6 +)

PS:此解决方案未经过优化,我有很多缺点。即:大量的指数,计算成本等。

答案 1 :(得分:1)

我刚遇到这个"差距"问题和我提出的解决方案是天真的,所以它可能效率不高,但我认为它很直接。

基本上耗尽(id, ind)对的所有组合,从原始DF我选择id的不同值并再次选择ind的不同值,然后将这两个结果交叉连接到获得所有组合。之后,只需将结果返回到原始DF,并将所有NA填充为0。