Apache spark 如果ID映射到窗口中的多个其他ID,则创建标志
我试图创建一个标志,显示哪些Apache spark 如果ID映射到窗口中的多个其他ID,则创建标志,apache-spark,pyspark,Apache Spark,Pyspark,我试图创建一个标志,显示哪些id1值在任意窗口n上重复映射到id2(n=2)。例如,给定此数据帧: df = spark.createDataFrame( [("2010-03-10", "A", "X"), ("2010-03-10", "A", "Y"), ("2010-03-10", "B", "Z"),
id1
值在任意窗口n
上重复映射到id2
(n=2
)。例如,给定此数据帧:
df = spark.createDataFrame(
[("2010-03-10", "A", "X"),
("2010-03-10", "A", "Y"),
("2010-03-10", "B", "Z"),
("2010-04-10", "A", "X"),
("2010-04-10", "A", "Y"),
("2010-04-10", "B", "Z"),
("2010-05-10", "A", "X"),
("2010-05-10", "A", "Y"),
("2010-05-10", "B", "Z"),
("2010-06-10", "A", "X"),
("2010-06-10", "B", "Z"),
("2010-07-10", "A", "X"),
("2010-07-10", "B", "Z")],
("date", "id1", "id2")
)
df.show()
+----------+---+---+
| date|id1|id2|
+----------+---+---+
|2010-03-10| A| X|
|2010-03-10| A| Y|
|2010-03-10| B| Z|
|2010-04-10| A| X|
|2010-04-10| A| Y|
|2010-04-10| B| Z|
|2010-05-10| A| X|
|2010-05-10| A| Y|
|2010-05-10| B| Z|
|2010-06-10| A| X|
|2010-06-10| B| Z|
|2010-07-10| A| X|
|2010-07-10| B| Z|
+----------+---+---+
预期产出:
+----------+---+---+--------+
| date|id1|id2|dup_flag|
+----------+---+---+--------+
|2010-03-10| A| X| 1|
|2010-03-10| A| Y| 1|
|2010-03-10| B| Z| 0|
|2010-04-10| A| X| 1|
|2010-04-10| A| Y| 1|
|2010-04-10| B| Z| 0|
|2010-05-10| A| X| 1|
|2010-05-10| A| Y| 1|
|2010-05-10| B| Z| 0|
|2010-06-10| A| X| 1|
|2010-06-10| B| Z| 0|
|2010-07-10| A| X| 0|
|2010-07-10| B| Z| 0|
+----------+---+---+--------+
其中,dup_flag
是一个标志,指示id1是否在过去2个月的某个地方包含到id2
的重复映射
也就是说,对于id1
B
,它从不映射到Z
以外的任何其他id2
,因此它从不被标记为重复。
对于
id1
A
我们有重复的映射。在本例中,我将窗口大小设置为2
,这意味着如果A
在最多一个月后的窗口的任何日期内映射到多个id2
(即当前月份以及上个月都应包含在窗口中),则它应收到一个标志。因此,A
接收此标志直到2010-07-10
,在这一时期,我们有一个由2010-06-10
和2010-07-10
组成的窗口,其中A
不映射到多个id2
(它只映射到该窗口中的id2
X
).解决这个问题的方法有些老套。实际上,您创建了一个基于范围而不是基于行的窗口,并在该窗口上执行countdistinct
。不知何故,Spark不支持后者,因此我需要通过使用size(collect\u set)
来绕过它,它本质上与count distinct
相同。另外,Spark不支持按日期排序的基于范围的窗口,因此我需要将该列转换为整数类型,并使用一个神奇的数字2678400,它等于31天内的秒数
import pyspark.sql.functions as F
from pyspark.sql.window import Window
### initialize df as in the question
### df = ...
df = df.withColumn('date', F.col('date').cast('timestamp').cast('bigint'))
flag = (F.size(F.collect_set(F.col('id2')).over(Window.partitionBy('id1').orderBy('date').rangeBetween(-2678400, 0))) > 1).cast('int')
df = df.withColumn('flag', flag)
df = df.withColumn('date', F.col('date').cast('timestamp').cast('date'))
这个想法有点像
COUNT DISTINCT id2 OVER (PARTITION BY id1 ORDER BY date RANGE BETWEEN INTERVAL '1' MONTH PRECEDING AND CURRENT ROW)
对于行
|2010-07-10 | A | X | 0 |
,标志不应该是1,因为2020-05-10上有重复的条目吗?标志应该是0,因为对于2
的窗口大小,当日期是2010-07-10
时,我只想查看2010-06-10
<代码>2010-05-10在这种情况下将被忽略。但您在最多两个月前的窗口内的任何日期内都说了。
;)你是对的,我错了。现在在文本中修复了它!谢谢你的回答。我发现解决方案没有将2010-06-10
标记为a
的重复条目,即使它在2010-05-10
中有重复映射。也许这是因为不是每个月都有30天。是的,那么也许我应该用31天来代替。我相信这仍然会引起问题,因为不是每个月都有31天。看来这个问题并不像我想象的那么简单,非常感谢你的帮助。啊,如果你只对此感兴趣的话,我应该提取月份并转换成整数!但接下来的一年会有一个问题,比如“2010-01”对“2009-12”