如何使用Pandas内置groupby与transform方法实现分组标准化处理?
优雅实现Pandas分组标准化需求
没问题,这需求用Pandas的groupby+transform完全可以优雅解决,而且非常符合Pythonic风格,不用写冗余的循环逻辑。
核心思路
按ex_date和id分组后,每个分组内找到calc_date等于ex_date的那一行的ref_value_1作为基准值,然后将该分组所有行的ref_value_1除以这个基准值,就得到标准化后的结果。
完整实现代码
首先先还原你的示例数据:
import pandas as pd # 示例输入数据 df = pd.DataFrame({ 'calc_date': ['1/1/2021', '2/1/2021', '3/1/2021', '1/1/2021', '2/1/2021', '3/1/2021', '1/1/2021', '2/1/2021', '3/1/2021', '1/1/2021', '2/1/2021', '3/1/2021'], 'ex_date': ['2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021', '2/1/2021'], 'id': [1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4], 'ref_value_1': [1.5, 3.0, 4.5, 5.0, 10.0, 15.0, 15.0, 40.0, 60.0, 75.0, 100.0, 120.0], 'bins': [1, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3] })
然后用groupby+transform实现标准化:
# 定义分组内的标准化函数 def standardize_group(group): # 获取当前分组中calc_date等于ex_date的ref_value_1作为基准值 base_value = group[group['calc_date'] == group['ex_date']]['ref_value_1'].iloc[0] # 分组内所有ref_value_1除以基准值 return group['ref_value_1'] / base_value # 按ex_date和id分组,应用transform生成标准化列 df['standardized_val'] = df.groupby(['ex_date', 'id']).transform(standardize_group)
验证结果
运行后查看df,得到的结果和你预期的完全一致:
| calc_date | ex_date | id | ref_value_1 | bins | standardized_val |
|---|---|---|---|---|---|
| 1/1/2021 | 2/1/2021 | 1 | 1.5 | 1 | 0.5 |
| 2/1/2021 | 2/1/2021 | 1 | 3.0 | 1 | 1.0 |
| 3/1/2021 | 2/1/2021 | 1 | 4.5 | 1 | 1.5 |
| 1/1/2021 | 2/1/2021 | 2 | 5.0 | 1 | 0.5 |
| 2/1/2021 | 2/1/2021 | 2 | 10.0 | 1 | 1.0 |
| 3/1/2021 | 2/1/2021 | 2 | 15.0 | 1 | 1.5 |
| 1/1/2021 | 2/1/2021 | 3 | 15.0 | 2 | 0.375 |
| 2/1/2021 | 2/1/2021 | 3 | 40.0 | 2 | 1.0 |
| 3/1/2021 | 2/1/2021 | 3 | 60.0 | 2 | 1.5 |
| 1/1/2021 | 2/1/2021 | 4 | 75.0 | 3 | 0.75 |
| 2/1/2021 | 2/1/2021 | 4 | 100.0 | 3 | 1.0 |
| 3/1/2021 | 2/1/2021 | 4 | 120.0 | 3 | 1.2 |
补充说明
- 这里假设每个
ex_date+id的分组里恰好有一行满足calc_date == ex_date,如果存在多行的话,可以根据需求调整(比如取均值、最大值等)。 - 如果日期列是字符串格式,直接比较没问题;如果是datetime类型,比较逻辑同样适用,不需要额外转换。
内容的提问来源于stack exchange,提问作者Winsor-Mavis
相关产品推荐
相关产品推荐

