Pandas使用crosstab生成自定义年份列统计唯一design_id数量
Pandas 按ID分组统计指定年份下的唯一design_id数量
现有数据结构
手上的DataFrame样例结构如下:
ID,design_id,year,output 1,21345,1978,1 1,3456,2019,1 1,5678,2021,1 1,7890,2021,1 1,5678,2021,2 1,1357,2020,3 2,9876,2021,8 2,9865,2021,1 2,9678,2021,0
需求说明
- 生成固定4个年份列:
year_2019、year_2020、year_2021、year_2022 - 按
ID维度分组聚合,对应年份列的值为该ID在当年关联的去重后design_id数量
已尝试的方案
之前参考相关内容写了两种实现,均未达到预期:
# 方案1 pd.crosstab( index=tf['ID'], columns=tf['year'], values=tf['design_id'], aggfunc='nunique').fillna(0) # 方案2 out = (pd .crosstab(df['ID'], df['year']) .reindex(range(2019, 2022+1), axis=1, fill_value=0) .add_prefix('year_') .reset_index() .rename_axis(columns=None) )
数据背景与预期输出
真实数据集共400万行,包含1970-2022年间的50个唯一年份值,不需要统计全量年份,仅需输出2019-2022四个年份的去重计数结果,统计口径为唯一design_id数量而非总记录条数。
期望输出格式如下:
ID,year_2019,year_2020,year_2021,year_2022 1,1,1,2,0 2,0,0,3,0
实现方案
两个原有方案的问题非常明确:
- 方案1未做列筛选和重命名,会输出1970-2022所有年份的结果,也没有自动补全无数据的年份(比如样例中2022年无数据,需要自动填充0)
- 方案2漏传
values和aggfunc参数,默认crosstab统计的是行出现频次,不会对design_id做去重计数,结果不符合要求。
针对400万行的数据集,优先先过滤目标年份再做聚合,减少不必要的计算量,性能表现更好:
# 指定要统计的目标年份 target_years = [2019, 2020, 2021, 2022] # 先过滤出目标年份的数据,压缩计算范围 df_filtered = df[df['year'].isin(target_years)] result = ( pd.crosstab( index=df_filtered['ID'], columns=df_filtered['year'], values=df_filtered['design_id'], aggfunc='nunique' ) # 补全所有目标年份,无数据的年份填0 .reindex(columns=target_years, fill_value=0) # 给年份列加统一前缀 .add_prefix('year_') # 把ID从索引转回普通列 .reset_index() # 清空列索引名称 .rename_axis(columns=None) )
如果习惯用groupby语法,也可以用下面的写法,性能和上面的crosstab实现基本持平,逻辑更直观:
target_years = [2019, 2020, 2021, 2022] result = ( df[df['year'].isin(target_years)] .groupby(['ID', 'year'])['design_id'] .nunique() .unstack(fill_value=0) .reindex(columns=target_years, fill_value=0) .add_prefix('year_') .reset_index() .rename_axis(columns=None) )
两种写法输出的结果和预期完全一致,400万行数据在普通消费级PC上也能在数秒内跑完,无性能瓶颈。
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

