
本文介绍如何在 PySpark DataFrame 中识别并去重无序水果组合(如 apple-orange-cherry 与 orange-apple-cherry 视为同一组合),再按计数降序保留 Top-N 行。核心方法是利用 array_sort 标准化组合顺序,结合窗口函数 row_number() 去重,最后排序截断。
本文介绍如何在 pyspark dataframe 中识别并去重无序水果组合(如 apple-orange-cherry 与 orange-apple-cherry 视为同一组合),再按计数降序保留 top-n 行。核心方法是利用 `array_sort` 标准化组合顺序,结合窗口函数 `row_number()` 去重,最后排序截断。
在处理多列构成的“集合型”特征(如水果组合)时,原始列顺序不固定会导致逻辑重复——例如 ('apple','orange','cherry') 和 ('orange','apple','cherry') 实质表示同一组合,但作为普通行无法被 dropDuplicates() 直接识别。PySpark 本身不提供原生集合去重,需通过标准化 + 窗口函数实现。
关键思路分三步:
-
标准化组合顺序:将
first_fruit,second_fruit,third_fruit合并为数组,并用array_sort()统一升序排列,确保相同元素组合生成完全一致的数组值; -
组内去重:以该排序后数组为分区键(
partitionBy),在每组内按count降序编号(row_number()),仅保留编号为1的首行; -
全局筛选 Top-N:对去重后的结果按
count降序排序,并用limit(N)截取前 N 行。
以下是完整可执行代码(适配 Spark 3.1+):
from pyspark.sql import functions as F
from pyspark.sql.window import Window
# 假设 df 是你的 PySpark DataFrame(注意:示例中 count 列为字符串,建议转为整型提升排序可靠性)
df_clean = df.withColumn("count_int", F.col("count").cast("int")) \
.withColumn(
"combo_sorted",
F.array_sort(F.array("first_fruit", "second_fruit", "third_fruit"))
) \
.withColumn(
"rank_in_combo",
F.row_number().over(
Window.partitionBy("combo_sorted")
.orderBy(F.desc("count_int"))
)
) \
.filter(F.col("rank_in_combo") == 1) \
.drop("combo_sorted", "rank_in_combo", "count_int") \
.orderBy(F.desc("count")) \
.limit(2)
✅ 注意事项:
- 若
count列为字符串类型(如示例中的'10','5'),务必先.cast("int")再排序,否则'10' > '5'字典序比较会出错; -
array_sort()要求 Spark ≥ 3.1;旧版本可用sort_array(array(...))替代; -
row_number()必须指定orderBy子句(即使count相同),否则报错;此处用count降序可保证高频组合优先保留; - 若组合列数不固定(如 2–5 种水果),建议提前将所有水果列收集为
array类型字段再排序,避免硬编码列名。
最终输出即为唯一组合 + Top-2 高频结果,完全匹配需求:保留 count=10 和 count=5 的两行,且每行水果列已自然有序(如 apple-orange-cherry),语义清晰、可扩展性强。










