You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySpark分组统计count异常,求原因及正确实现方案

问题原因分析

你的PySpark代码中第一个join的关联条件完全错误,这是导致thing_rate不一致的核心原因:

原代码中的join条件写的是:

(df_count_per_category.thing== df_count_per_category.thing) & (df_count_per_category.category== df_count_per_category.category)

这是将df_count_per_category的字段与自身做相等判断,这个条件永远为真,会导致原df的每一行都和df_count_per_category的所有行进行关联(笛卡尔积)。最终df_merge中会混入不属于当前行的thing_count值,虽然同一事物的行可能碰巧拿到正确的thing_count,但错误的关联会让部分行的thing_count对应其他事物的数值,计算出的thing_rate自然混乱。

修正方案

有两种修正思路,推荐使用窗口函数(和你R代码的逻辑完全一致,更简洁高效):

方案1:使用窗口函数(推荐,对齐R语言逻辑)

直接用窗口函数按category和category,thing分组计算统计值,无需多次join:

from pyspark.sql import Window
import pyspark.sql.functions as F

# 按category和thing分组,计算每个事物的记录数
window_thing = Window.partitionBy("category", "thing")
# 按category分组,计算分类下总记录数
window_category = Window.partitionBy("category")

df_result = df.withColumn("thing_count", F.count("*").over(window_thing)) \
              .withColumn("thing_total", F.count("*").over(window_category)) \
              .withColumn("thing_rate", F.round(F.col("thing_count") / F.col("thing_total"), 4)) \
              .select("category", "thing", "thing_count", "thing_total", "thing_rate") \
              .distinct()  # 去重,保留唯一的category-thing组合

df_result.show()

方案2:修正join条件

如果坚持用join的方式,需要把第一个join的条件改成原df和df_count_per_category的字段关联:

# 原统计部分不变
df_count_per_category = df.select('category', 'thing') \
                          .groupby('category', 'thing') \
                          .agg(F.count('*').alias('thing_count'))

df_total = df.select('category') \
             .groupby('category') \
             .agg(F.count('*').alias('thing_total'))

# 修正第一个join的关联条件
df_merge = df.join(df_count_per_category, 
                   on=[df.category == df_count_per_category.category, 
                       df.thing == df_count_per_category.thing], 
                   how='inner') \
             .drop(df_count_per_category.thing) \
             .drop(df_count_per_category.category) \
             .join(df_total, on=[df.category == df_total.category], how='inner') \
             .drop(df_total.category)

df_rate = df_merge.withColumn('thing_rate', F.round(F.col('thing_count') / F.col('thing_total'), 4)) \
                  .select("category", "thing", "thing_count", "thing_total", "thing_rate") \
                  .distinct()

df_rate.show()
预期输出

两种方案都会得到和你R代码一致的结果:

+---------+-----+-----------+------------+----------+
|category|thing|thing_count|thing_total|thing_rate|
+---------+-----+-----------+------------+----------+
|        A|    X|          3|           6|     0.5000|
|        A|    Y|          1|           6|     0.1667|
|        A|    Z|          2|           6|     0.3333|
|        B|    X|          1|           3|     0.3333|
|        B|    Y|          1|           3|     0.3333|
|        B|    Z|          1|           3|     0.3333|
+---------+-----+-----------+------------+----------+

内容的提问来源于stack exchange,提问作者user10443249

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 15:25:09