计算DF中的出现次数和同时发生次数

时间:2016-07-29 06:40:51

标签: scala apache-spark

我想在Spark数据框中计算两个变量xy之间的mutual information(MI),如下所示:

scala> df.show()
+---+---+
|  x|  y|
+---+---+
|  0| DO|
|  1| FR|
|  0| MK|
|  0| FR|
|  0| RU|
|  0| TN|
|  0| TN|
|  0| KW|
|  1| RU|
|  0| JP|
|  0| US|
|  0| CL|
|  0| ES|
|  0| KR|
|  0| US|
|  0| IT|
|  0| SE|
|  0| MX|
|  0| CN|
|  1| EE|
+---+---+

在我的情况下,x恰好是事件是否发生(x = 1)与否(x = 0),而y是国家/地区代码,但这些变量可以代表什么。要计算xy之间的MI,我希望上述数据框按x, y对分组,并附加以下三列:

  • x
  • 的出现次数
  • y
  • 的出现次数
  • x, y
  • 的出现次数

在上面的简短示例中,它看起来像

x, y, count_x, count_y, count_xy
0, FR, 17, 2, 1
1, FR, 3, 2, 1
...

然后我只需计算每个x, y对的互信息项并求它们。

到目前为止,我已经能够按x, y对进行分组并汇总count(*)列,但我找不到有效的方法来添加x和{{1}计数。我目前的解决方案是将DF转换为数组并手动计算出现次数和同现次数。当y是一个国家/地区时效果很好但是当y的基数变大时它会永远存在。有关如何以更多 Sparkish 方式进行操作的任何建议吗?

提前致谢!

3 个答案:

答案 0 :(得分:2)

我会使用RDD,为每个用例生成一个密钥,按键计数并加入结果。这样我就知道到底是什么阶段。

rdd.cache() // rdd is your data [x,y]
val xCnt:RDD[Int, Int] = rdd.countByKey
val yCnt:RDD[String, Int] = rdd.countByValue
val xyCnt:RDD[(Int,String), Int] = rdd.map((x, y) => ((x,y), x,y)).countByKey
val tmp = xCnt.cartsian(yCnt).map(((x, xCnt),(y, yCnt)) => ((x,y),xCnt,yCnt))
val miReady = tmp.join(xyCnt).map(((x,y), ((xCnt, yCnt), xyCnt)) => ((x,y), xCnt, yCnt, xyCnt))

另一种选择是使用地图分区,只需处理迭代,并在分区之间合并resolute。

答案 1 :(得分:1)

Spark也是新手,但我知道该怎么做。我不知道这是否是完美的解决方案,但我认为分享这不会有害。

我要做的可能是filter()为值1创建一个Dataframe,filter()为值0为第二个Dataframe

你会得到像

这样的东西

1st Dataframe

DO 1
DO 1
FR 1

在下一步中,我将分组(y)

所以你会得到第一个Dataframe

DO 1 1

FR 1

作为GroupedData https://spark.apache.org/docs/1.4.0/api/java/org/apache/spark/sql/GroupedData.html

这也有一个count()函数,它应该计算每组的行数。不幸的是,我现在没有时间自己尝试这个,但无论如何我想尝试帮助。

编辑:如果这有帮助,请告诉我,否则我会删除答案,以便其他人仍然看看这个!

答案 2 :(得分:0)

最近,我有同样的任务来计算概率,在这里我想基于Spark的窗口聚合函数分享我的解决方案:

// data is your DataFrame with two columns [x,y]
val cooccurrDF: DataFrame = data
  .groupBy(col("x"), col("y"))
  .count()
  .toDF("x", "y", "count-x-y")

val windowX: WindowSpec = Window.partitionBy("x")
val windowY: WindowSpec = Window.partitionBy("y")

val countsDF: DataFrame = cooccurrDF
  .withColumn("count-x", sum("count-x-y") over windowX)
  .withColumn("count-y", sum("count-x-y") over windowY)
countsDF.show()

首先,您将两列的每个可能组合分组,并使用count来获取同现数。窗口聚合windowX和windowY允许对聚合行求和,因此您将获得列x或y的计数。

+---+---+---------+-------+-------+
|  x|  y|count-x-y|count-x|count-y|
+---+---+---------+-------+-------+
|  0| MK|        1|     17|      1|
|  0| MX|        1|     17|      1|
|  1| EE|        1|      3|      1|
|  0| CN|        1|     17|      1|
|  1| RU|        1|      3|      2|
|  0| RU|        1|     17|      2|
|  0| CL|        1|     17|      1|
|  0| ES|        1|     17|      1|
|  0| KR|        1|     17|      1|
|  0| US|        2|     17|      2|
|  1| FR|        1|      3|      2|
|  0| FR|        1|     17|      2|
|  0| TN|        2|     17|      2|
|  0| IT|        1|     17|      1|
|  0| SE|        1|     17|      1|
|  0| DO|        1|     17|      1|
|  0| JP|        1|     17|      1|
|  0| KW|        1|     17|      1|
+---+---+---------+-------+-------+