使用groupby后如何计算各年龄组产品销量的同比增长率?
问题描述
我有如下示例数据:
pd.DataFrame({'date': {0: Timestamp('2021-08-01 00:00:00'), 1: Timestamp('2022-08-01 00:00:00'), 2: Timestamp('2021-08-01 00:00:00'), 3: Timestamp('2021-08-01 00:00:00'), 4: Timestamp('2022-08-01 00:00:00'), 5: Timestamp('2022-08-01 00:00:00')}, 'customer_nr': {0: 2, 1: 3, 2: 2, 3: 3, 4: 2, 5: 2}, 'product_nr': {0: 3, 1: 2, 2: 2, 3: 1, 4: 2, 5: 1}, 'age': {0: 32.0, 1: 32.0, 2: 32.0, 3: 32.0, 4: 32.0, 5: 37.0}, 'gender': {0: 'M', 1: 'M', 2: 'M', 3: 'M', 4: 'M', 5: 'M'}, 'age_group': {0: '25-34', 1: '25-34', 2: '25-34', 3: '25-34', 4: '25-34', 5: '35-44'}} )
执行分组操作:
df.groupby(['date','product_nr','age_group']).age.count().unstack()
得到结果:
| date | product_nr | 25-34 | 35-44 |
|---|---|---|---|
| 2021-08-01 | 1 | 1 | NaN |
| 2 | 1 | NaN | |
| 3 | 1 | NaN | |
| 2022-08-01 | 1 | NaN | 1 |
| 2 | 2 | NaN |
现在需要计算从第一个日期到第二个日期,各年龄组下产品销量的增长百分比,期望得到如下格式的结果:
| product_nr | 25-34 | 35-44 | 45-54 | 55-64 |
|---|---|---|---|---|
| 1 | x% | x% | x% | x% |
| 2 | x% | x% | x% | x% |
| 3 | x% | x% | x% | x% |
注:原始数据集包含更多产品和客户,且两年的product_nr数量和排序不一致。
解决方案
通过以下步骤可实现需求:
- 重塑分组结果结构:将多层索引数据转换为宽表,让日期成为独立列,便于计算增长。
- 填充缺失值:用0填充NaN,避免因两年产品/年龄组不匹配导致的计算错误。
- 计算增长百分比:按公式
(后期销量-前期销量)/前期销量*100计算增长率,同时处理前期销量为0的特殊情况(如新增产品)。 - 整理目标格式:调整结果为以
product_nr为索引、各年龄组为列的结构。
具体代码如下:
# 执行分组操作并保存结果 grouped = df.groupby(['date','product_nr','age_group']).age.count().unstack(fill_value=0) # 转换多层索引为列,方便后续处理 grouped_flat = grouped.reset_index() # 提取两个日期(假设日期为升序排列) date1, date2 = grouped_flat['date'].unique() # 分别筛选两年数据,设置product_nr为索引 df_year1 = grouped_flat[grouped_flat['date'] == date1].set_index('product_nr').drop('date', axis=1) df_year2 = grouped_flat[grouped_flat['date'] == date2].set_index('product_nr').drop('date', axis=1) # 对齐两年的产品和年龄组,缺失值用0填充 df_aligned = df_year2.join(df_year1, how='outer', lsuffix='_y2', rsuffix='_y1').fillna(0) # 计算增长百分比,处理除数为0的情况 for col in df_year1.columns: df_aligned[col] = df_aligned.apply( lambda row: ((row[f'{col}_y2'] - row[f'{col}_y1'])/row[f'{col}_y1'])*100 if row[f'{col}_y1'] !=0 else 100, axis=1 ) # 整理成目标格式 result = df_aligned[[col for col in df_year1.columns]].reset_index() # 可选:将数值格式化为百分比显示 result = result.style.format({col: '{:.2f}%' for col in result.columns if col != 'product_nr'})
执行后即可得到符合要求的结果,原始数据中的其他年龄组会自动被识别处理。
内容的提问来源于stack exchange,提问作者user19495470
相关产品推荐
相关产品推荐

