情况如下:我有一个时序数据帧,它由一个索引列组成,该索引列对序列进行排序;和一些离散值的列,如下所示:
id value
0 A
1 A
2 B
3 C
4 A
5 A
6 A
7 B
我现在要减少所有连续重复项,使其看起来像这样:
id value
0 A
2 B
3 C
4 A
7 B
我想出了一个窗口,然后使用lag()
,when()
进行过滤。问题在于窗口需要特定的分区列。但是,我想要的是先在每个分区中删除连续的行,然后再检查分区边界(由于该窗口对每个分区均有效,因此在分区边界上的连续行仍然存在)。
df_with_block = df.withColumn(
"block", (col("id") / df.rdd.getNumPartitions()).cast("int"))
window = Window.partitionBy("block").orderBy("id")
get_last = when(lag("value", 1).over(window) == col("value"), False).otherwise(True)
reduced_df = unificated_with_block.withColumn("reduced",get_last)
.where(col("reduced")).drop("reduced")
在第一行中,我创建了一个新的数据帧,该数据帧通过将ID整数除以均匀分布的分区。然后,get_last包含布尔值,具体取决于当前行是否等于前一行。 reduce_df然后将重复项过滤掉。
现在的问题是分区边界:
id value
0 A
2 B
3 C
4 A
6 A
7 B
如您所见,id = 6的行没有被删除,因为它是在另一个分区中处理的。我正在考虑不同的想法来解决这个问题:
coalesce()
合并分区并再次过滤吗?我很好奇这怎么解决。
答案 0 :(得分:0)
您可以使用没有分区的窗口,使用已经使用的相同逻辑。
from pyspark.sql.window import *
import pyspark.sql.functions as F
data = [(0,"A"), (1,"A"),(2,"B"),(3,"C"),(4,"A"),(5,"A"),(6,"A"),(7,"B")]
df = sqlContext.createDataFrame(data, ["id","value"])
w = Window().orderBy(F.col("id"))
df = df.withColumn("dupe", F.col("value") == F.lag("value").over(w))\
.filter((F.col("dupe") == False) | (F.col("dupe").isNull())).drop("dupe")
df.show()
结果:
+---+-----+
| id|value|
+---+-----+
| 0| A|
| 2| B|
| 3| C|
| 4| A|
| 7| B|
+---+-----+
另一种分区方法是按值分区,结果是: 假设重复记录的ID仅增加1。
w = Window().partitionBy("value").orderBy(F.col("id"))
df = df.withColumn("dupe", F.col("id") - F.lag("id").over(w))\
.filter((F.col("dupe") > 1) | (F.col("dupe").isNull())).drop("dupe")\
.orderBy("id")