如何高效计算分组下的唯一值数量:按年份 类别 及组合维度

作者:袖梨 2026-06-19

本文介绍使用 Pandas 的 groupby().transform() 方法,一行代码即可为原始 DataFrame 同时添加多个分组维度下的唯一值计数列,避免冗余的 merge 操作,提升可读性与执行效率。

本文介绍使用 pandas 的 `groupby().transform()` 方法,一行代码即可为原始 dataframe 同时添加多个分组维度下的唯一值计数列,避免冗余的 merge 操作,提升可读性与执行效率。

在数据分析中,常需统计某字段(如观测 ID i)在不同分组层级下的唯一值数量——例如按类别(cat)、按年份(year)、或按二者组合(year + cat)分别统计不重复的 i 数量。传统做法是分别调用 groupby().nunique() 生成聚合结果,再通过多次 merge 回原表,不仅代码冗长,还易因索引对齐问题引入错误。

更优雅、高效的方案是利用 transform() 方法:它能在保持原始 DataFrame 行数和顺序不变的前提下,将分组聚合结果广播回每行,天然适配“为每行标注所属分组的统计指标”这类需求。

以下为推荐实现方式:

import pandas as pddf = pd.DataFrame({    'year': [2020, 2020, 2020, 2021, 2021, 2022, 2023, 2023, 2023, 2023],    'cat':  [1,    1,    2,    2,    3,    3,    1,    2,    3,    4],    'i':    ['a',  'a',  'b',  'c',  'd',  'e',  'f',  'f',  'g',  'g']})# 定义所有需要统计的分组维度groups = ['cat', 'year', ['cat', 'year']]# 批量添加新列:n_by_cat、n_by_year、n_by_catyearfor g in groups:    col_name = f"n_by_{''.join(map(str, g))}" if isinstance(g, list) else f"n_by_{g}"    df[col_name] = df.groupby(g)['i'].transform('nunique')

运行后,df 将直接包含三列新增统计字段,每行均准确反映其所在分组内 i 的唯一值数量:

year cat i n_by_cat n_by_year n_by_catyear
2020 1 a 2 2 1
2020 1 a 2 2 1
... ... ... ... ... ...

优势总结

  • 简洁性:无需创建中间聚合表,避免 merge 带来的列重命名与键匹配风险;
  • 一致性:transform 保证输出长度与原 DataFrame 严格一致,无索引错位隐患;
  • 可扩展性:只需向 groups 列表追加新分组(如 ['year', 'cat', 'region']),即可一键扩展统计维度;
  • 性能友好:相比多次 merge,transform 在底层做了优化,尤其在大数据集上表现更优。

⚠️ 注意事项

  • transform('nunique') 要求被统计列(此处为 'i')支持哈希比较(如字符串、数值、元组等),不可为含 NaN 的混合类型对象列;
  • 若分组键含缺失值(NaN),Pandas 默认将其视为独立组;如需忽略,可先 dropna(subset=['cat', 'year']);
  • 列名生成逻辑已适配单列与多列分组(如 ['cat', 'year'] → 'n_by_catyear'),实际项目中建议根据业务语义自定义更清晰的列名(如 n_distinct_i_by_cat)。

掌握 transform 的这一典型用法,能显著简化分组统计类任务,是 Pandas 高效数据工程实践的关键技巧之一。

相关文章

精彩推荐