Scala 计算DF中的发生次数和共发生次数

Scala 计算DF中的发生次数和共发生次数,scala,apache-spark,Scala,Apache Spark,我想计算Spark数据框中两个变量x和y之间的(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|

我想计算Spark数据框中两个变量
x
y
之间的(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
是一个国家代码,但这些变量可以代表任何东西。要计算
x
y
之间的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
y
计数。我目前的解决方案是将DF转换成一个数组,并手动计算发生次数。当
y
是一个国家时,它工作得很好,但当
y
的基数变大时,它需要永远。有什么建议可以让我用一种更简单的方式来做吗


提前谢谢

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

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

你会得到这样的结果

第一数据帧

DO 1
DO 1
FR 1

在下一步中,我将使用groupBy(y)

所以你会得到第一个数据帧

做1 1

FR 1

作为组数据

这还有一个count()函数,它应该计算每个组的行数。不幸的是,我现在没有时间亲自尝试,但我还是想尝试帮助别人


编辑:请让我知道这是否有帮助,否则我会删除答案,让其他人仍然看这个

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

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

你会得到这样的结果

第一数据帧

DO 1
DO 1
FR 1

在下一步中,我将使用groupBy(y)

所以你会得到第一个数据帧

做1 1

FR 1

作为组数据

这还有一个count()函数,它应该计算每个组的行数。不幸的是,我现在没有时间亲自尝试,但我还是想尝试帮助别人


编辑:请让我知道这是否有帮助,否则我会删除答案,让其他人仍然看这个

我会使用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))

另一种选择是使用map Partition,只需处理iterables,并在分区之间合并resolutes。

我会使用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))

另一种选择是使用map Partition,只需处理iterables并在分区之间合并resolutes。

最近,我有同样的任务来计算概率,我想在这里分享我基于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|
+---+---+---------+-------+-------+

最近,我有同样的任务来计算概率,在这里我想分享我基于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|
+---+---+---------+-------+-------+

谢谢你的回答。这个解决方案是我暂时采用的,但我不确定它是否会推广到y的基数为3或更多的情况。粗略地说,它包括显式地生成笛卡尔积(同时考虑到
y
只能取两个值)。我认为@z-star提出了一个更全面的答案。但是,请不要删除您的答案,它仍然有效,可能对其他用户有用,其他贡献者可能会帮助您改进它。谢谢您的答案。这个解决方案是我暂时采用的,但我不确定它是否会推广到y的基数为3或更多的情况。粗略地说,它包括显式地生成笛卡尔积(同时考虑到
y
只能取两个值)。我认为@z-star提出了一个更全面的答案。但是,请不要删除您的答案,它仍然有效,可能对其他用户有用,其他贡献者可能会帮助您改进它。