如何从一个列中删除所有子集,除了少数基于 Pyspark 中的其他列?

How to remove all the subset from a column except few based on the other column in Pyspark?

我有一个 pyspark 数据框,其中有一列列表(列 a)和另一列数字(列 b),我想保留所有超集行和子集在 b 列中的值大于它们的超集。

例如,

输入数据帧:

Column a = ([A,B,C],[A,C],[B,C],[J,S,K],[J,S],[J,K])
Column b = (10,15,7,8,9,8)

预期结果:

Column a = ([A,B,C],[A,C],[J,S,K],[J,S])
Column b = (10,15,8,9)

这里 [B,C][A,C][A,B,C] 的子集,但我们只保留 [A,C] 因为这个子集在 b 列中有 15大于 10b 中的超集 ([A,B,C]) 值。 同样,超集 [J,S,K] 与其子集 [J,S] 一起保留,因为它在列 b 中的值大于超集列 b 的值。

您可以使用自 left_anti 连接来过滤满足该条件的行。

您的数据框中需要有一个 ID 列,这里我使用 monotonically_increasing_id 函数为每一行生成一个 ID

import pyspark.sql.functions as F

df = df.withColumn("ID", F.monotonically_increasing_id())
df.show() 

#+---------+---+-----------+
#|        a|  b|         ID|
#+---------+---+-----------+
#|[A, B, C]| 10| 8589934592|
#|   [A, C]| 15|17179869184|
#|   [B, C]|  7|25769803776|
#|[J, S, K]|  8|42949672960|
#|   [J, S]|  9|51539607552|
#|   [J, K]|  8|60129542144|
#+---------+---+-----------+

现在,要验证数组 arr1 是另一个数组 arr2 的子集,您可以使用 array_intersectsize 函数 size(array_intersect(arr1, arr2)) = size(arr1):

df_result = df.alias("df1").join(
    df.alias("df2"),
    (
        (F.size(F.array_intersect("df1.a", "df2.a")) == F.size("df1.a"))
        & (F.col("df1.b") <= F.col("df2.b"))
        & (F.col("df1.ID") != F.col("df2.ID")) # not the same row
    ),
    "left_anti"
).drop("ID")

df_result.show()

#+---------+---+
#|        a|  b|
#+---------+---+
#|[A, B, C]| 10|
#|   [A, C]| 15|
#|[J, S, K]|  8|
#|   [J, S]|  9|
#+---------+---+