Pandas计算并透视获取前两个自定义财年的营收数据
问题描述
给定如下DataFrame:
df = pd.DataFrame( {'stud_id' : [101, 101, 101, 101, 101, 102, 102, 102], 'sub_code' : ['CSE01', 'CSE01', 'CSE01', 'CSE01', 'CSE02', 'CSE02', 'CSE02', 'CSE02'], 'ques_date' : ['10/11/2022', '06/06/2022','09/04/2022', '27/03/2022', '13/05/2010', '10/11/2021','11/1/2022', '27/02/2022'], 'revenue' : [77, 86, 55, 90, 65, 90, 80, 67]} ) df['ques_date'] = pd.to_datetime(df['ques_date'])
需完成以下操作:
- a) 按自定义财历计算财年:10-12月为Q1,1-3月为Q2,4-6月为Q3,7-9月为Q4
- b) 按
stud_id分组 - c) 计算截止日期20/12/2022前两个自定义财年的营收总和(截止日期处于FY-2023,需统计FY-2022和FY-2021的营收)
尝试了以下代码,但输出列不符合预期:
df['custom_qtr'] = pd.to_datetime(df['ques_date'], dayfirst=True).dt.to_period('Q-SEP') date_1 = pd.to_datetime('20-12-2022') # CUT-OFF DATE df['custom_year'] = df['custom_qtr'].astype(str).str.extract('(?P<year>\d+)') df['date_based_qtr'] = date_1.to_period('Q-SEP') df['custom_date_year'] = df['date_based_qtr'].astype(str).str.extract('(?P<year>\d+)') df['custom_year'] = df['custom_year'].astype(int) df['custom_date_year'] = df['custom_date_year'].astype(int) df['diff'] = df['custom_date_year'].sub(df['custom_year']) df = df[df['diff'].isin([1,2])] out_df = df.pivot_table("revenue", index=['stud_id'],columns=['custom_year'],aggfunc=['sum']).add_prefix('rev_').reset_index().droplevel(0,axis=1)
当前输出存在列层级混乱、数据统计偏差问题,期望输出如下:
| stud_id | FY_2021 | FY_2022 |
|---|---|---|
| 101 | 0 | 308 |
| 102 | 90 | 147 |
解决方案
核心思路
你的自定义财历本质是财年以9月为结束节点(10月开启新财年),可以利用pandas的周期类型直接匹配该规则,再精准筛选目标财年数据后分组求和。
修正后的代码
import pandas as pd # 初始化数据并转换日期格式 df = pd.DataFrame( {'stud_id' : [101, 101, 101, 101, 101, 102, 102, 102], 'sub_code' : ['CSE01', 'CSE01', 'CSE01', 'CSE01', 'CSE02', 'CSE02', 'CSE02', 'CSE02'], 'ques_date' : ['10/11/2022', '06/06/2022','09/04/2022', '27/03/2022', '13/05/2010', '10/11/2021','11/1/2022', '27/02/2022'], 'revenue' : [77, 86, 55, 90, 65, 90, 80, 67]} ) df['ques_date'] = pd.to_datetime(df['ques_date'], dayfirst=True) # 计算自定义财年:Q-SEP表示财年结束于9月,提取年份即为财年编号 df['fy'] = df['ques_date'].dt.to_period('Q-SEP').dt.year # 确定截止日期对应的财年 cutoff_date = pd.to_datetime('20/12/2022', dayfirst=True) cutoff_fy = cutoff_date.to_period('Q-SEP').year # 筛选目标财年:截止财年的前两个财年 target_fys = [cutoff_fy - 2, cutoff_fy - 1] filtered_df = df[df['fy'].isin(target_fys)] # 分组求和并转换为宽表,缺失财年填充0 result = filtered_df.groupby(['stud_id', 'fy'])['revenue'].sum().unstack(fill_value=0) # 重命名列并固定列顺序 result = result.rename(columns={fy: f'FY_{fy}' for fy in target_fys}).reset_index() result = result[['stud_id', 'FY_2021', 'FY_2022']] print(result)
输出结果
stud_id FY_2021 FY_2022 0 101 0 308 1 102 90 147
代码说明
- 财年计算:
dt.to_period('Q-SEP')直接匹配"10月启新财年"的规则,提取的年份就是财年编号(例如2022年10月属于FY2023,2022年9月属于FY2022) - 筛选逻辑:截止日期2022-12-20属于FY2023,因此取前两个财年FY2021、FY2022的数据
- 分组重塑:用
groupby+unstack生成宽表,fill_value=0确保无数据的财年显示0值 - 列名优化:重命名列使其更直观,同时固定列顺序匹配期望输出
内容的提问来源于stack exchange,提问作者The Great
相关产品推荐
相关产品推荐

