Scala 计算DF中的发生次数和共发生次数
我想计算Spark数据框中两个变量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|
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提出了一个更全面的答案。但是,请不要删除您的答案,它仍然有效,可能对其他用户有用,其他贡献者可能会帮助您改进它。