
本文介绍使用 groupby().transform('nunique') 一行代码为 DataFrame 同时添加多个维度(如按类别、年份、组合)的唯一 ID 计数列,避免冗余合并操作,提升代码可读性与执行效率。
本文介绍使用 `groupby().transform('nunique')` 一行代码为 dataframe 同时添加多个维度(如按类别、年份、组合)的唯一 id 计数列,避免冗余合并操作,提升代码可读性与执行效率。
在实际数据分析中,常需对同一数据集按不同粒度统计唯一观测值(如用户 ID、样本编号等)的数量,并将结果作为新列回填至原始表中。传统做法(如多次 groupby().nunique() + merge)不仅代码冗长,还易因索引错位或重复键引发意外错误,且性能随分组维度增加而显著下降。
Pandas 提供了更优雅的解决方案:transform() 方法。它能在保持原始 DataFrame 行数和顺序不变的前提下,将聚合结果广播回每行——这正是我们所需的核心能力。
以下为推荐实现方式:
import pandas as pd
df = 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']
})
# 一次性为多组分组生成唯一计数列
group_specs = ['cat', 'year', ['cat', 'year']]
for spec in group_specs:
col_name = f"n_by_{'_'.join(map(str, spec))}" # 兼容单列与多列命名(如 ['cat','year'] → 'cat_year')
df[col_name] = df.groupby(spec)['i'].transform('nunique')
执行后,df 将新增三列:
- n_by_cat:该类别下所有年份中 i 的去重总数;
- n_by_year:该年份中所有类别下 i 的去重总数;
- n_by_cat_year:该年份+该类别组合下 i 的去重总数。
✅ 优势总结:
- 零合并:无需 merge,杜绝键不匹配、笛卡尔积膨胀等风险;
- 高可读性:逻辑集中、命名清晰,便于维护与扩展;
- 高性能:transform 内部优化良好,比多次 groupby().nunique() + map 或 merge 更快;
- 灵活扩展:新增分组维度只需向 group_specs 列表追加元组,例如 ['cat', 'year', 'i'] 或 ['year', 'cat', 'region']。
⚠️ 注意事项:
- transform('nunique') 要求被聚合列(此处为 'i')支持哈希操作(如字符串、数字、元组),不可为含 NaN 的混合类型或不可哈希对象;
- 若原始数据含缺失值(NaN)在分组列中,groupby 默认会自动排除这些行;若需保留,可设置 dropna=False(Pandas ≥ 1.5);
- 列名生成建议使用 '_'.join(map(str, spec)) 而非 ''.join(spec),避免数字列表转字符串时歧义(如 [1, 10] → '110' 错误),确保语义准确。
掌握 transform('nunique') 是 Pandas 高效分组统计的关键技巧之一,适用于用户活跃度分析、品类覆盖评估、跨维度去重归因等多种场景。











