将连续的重复项放在Spark数据框中

时间:2019-07-16 09:01:06

标签: pyspark apache-spark-sql time-series partitioning pyspark-sql

情况如下:我有一个时序数据帧,它由一个索引列组成,该索引列对序列进行排序;和一些离散值的列,如下所示:

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()合并分区并再次过滤吗?
  • 找到从下一个分区访问第一个值的方法
  • 使用RDD代替数据框来完成所有这些操作
  • 更改我的分区功能,以使其不会在重复副本所在的地方剪切(如何?)

我很好奇这怎么解决。

1 个答案:

答案 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")