跳转到主内容
websoft网络软件专家 - 深耕网络技术,打造实用软件!

如何在 PySpark DataFrame 中基于窗口计算去重计数

本文介绍如何使用 PySpark 的窗口函数(Window)配合 count() 实现按指定列分组后对某列的去重数量统计,并以 withColumn 方式添加新列,解决多行重复导致的非预期计数问题。 本文介绍如何使用 pyspark 的窗口函数(window)配合 `count()` 实现按指定列分组后对某列的**去重数量统计**,并以 `withcolumn` 方式添加新列,解决多行重复导致的非预期计数问题。 在 PySpark 中,直接使用 count(col('user_id')).over(window_spec) 默认执行的是总行数计数,而非去重计数(distinct count) 。因此,若原始数据中存在重复 user_id(如示例中 FWE + QRS 组合下 user_id=123 出现两次),上述写法会返回该分组的总记录数(3 行 → un_count=3),而非期望的唯一用户数(2 个不同 user_id:123 和 223)。 ✅ 正确做法是使用 countDistinct() 窗口聚合函数:
from pyspark.sql import Window from pyspark.sql.functions import countDistinct, col # 定义窗口:按 plan 和 name 分组 window_spec = Window.partitionBy('plan', 'name') # 添加新列 un_count:每个 (plan, name) 组内 user_id 的去重数量 df = df.withColumn('un_count', countDistinct('user_id').over(window_spec))
⚠️ 注意事项: countDistinct() 是 PySpark 3.0+ 推荐的标准函数;旧版本可使用 approx_count_distinct()(近似去重,性能更高但有误差)或通过子查询 + agg() + join 实现精确去重(不推荐,复杂且低效); 窗口函数无法直接在 countDistinct() 中嵌套 distinct 关键字(如 count(distinct 'user_id') 语法非法); 若需兼容 Spark 2.x 且必须精确计数,可改用 collect_set('user_id').over(window_spec) 获取去重集合,再用 size() 计算长度(但内存开销大,不适用于海量唯一值):
from pyspark.sql.functions import collect_set, size df = df.withColumn('un_count', size(collect_set('user_id')).over(window_spec))
最终输出将严格匹配预期结果:FWE/QRS 组返回 un_count=2(对应 user_id 123 和 223),RWE/QRS 组返回 un_count=1(仅 user_id=223),每行均携带所属窗口的去重统计值,满足分析与报表场景需求。

相关文章