Pandas如何基于条件获取前序DataFrame行数据补全任职记录
实现方案
核心思路
这种「组首行为公司总览、后续行为同公司岗位明细」的结构化数据,不用逐行遍历写判断,用pandas的分组填充+窗口函数就能高效实现,核心步骤如下:
- 识别组首行:判断
Period字段是否包含-(带空格的横杠,避免和日期内的分隔符混淆),凡是符合的就是公司总览行,用累计求和生成唯一分组ID,同公司的所有行共享同一个分组ID。 - 向下填充组信息:把每个组的公司名称、公司总任职结束日期填充到同组所有岗位明细行,明细行直接拿填充好的公司名拼接岗位名即可。
- 日期计算:先把所有日期列转为datetime格式,同组内取后一个岗位的开始日期减1天,作为前一个岗位的结束日期;每组最后一个岗位没有后续岗位,直接填充该公司的总任职结束日期。
- 清理辅助计算用的临时列,把日期转回原字符串格式,就得到目标结果。
可运行完整代码
import pandas as pd # 初始化原始数据集 data = [['Period', 'Company/Title', 'Personnel No.', 'Start Date', 'End Date'], ['01/01/1980 - 31/12/1982', 'AAA', '0', '01/01/1980', '31/12/1982'], ['01/01/1980', 'Typist', '0', '01/01/1980', ''], ['01/07/1990 - 31/05/1994', 'BBB', '0', '01/07/1990', '31/05/1994'], ['01/07/1990', 'Clerk 1', '0', '01/07/1990', ''], ['01/01/1994', 'Clerk 2', '0', '01/01/1994', ''], ['01/12/1993 - 05/06/1994', 'ZZZ', '1', '01/12/1993', '05/06/1994'], ['01/12/1993', 'Executive', '1', '01/12/1993', '']] # 注:原始数据最后一行岗位名误写为ZZZ,此处修正为Executive和期望输出对齐 data_df = pd.DataFrame(data[1:], columns=data[0]) # Step1:生成分组ID data_df['is_company_header'] = data_df['Period'].str.contains(' - ', regex=False) data_df['group_id'] = data_df['is_company_header'].cumsum() # Step2:提取每个分组的公司信息并向下填充 company_meta = data_df[data_df['is_company_header']].groupby('group_id').agg( company_name = ('Company/Title', 'first'), company_total_end = ('End Date', 'first') ).reset_index() data_df = data_df.merge(company_meta, on='group_id', how='left') # Step3:日期列转datetime类型用于计算 data_df['Start Date'] = pd.to_datetime(data_df['Start Date'], format='%d/%m/%Y') data_df['company_total_end'] = pd.to_datetime(data_df['company_total_end'], format='%d/%m/%Y') # Step4:拼接岗位明细行的Company/Title字段 data_df.loc[~data_df['is_company_header'], 'Company/Title'] = ( data_df['company_name'] + ' - ' + data_df['Company/Title'] ) # Step5:计算各岗位的End Date data_df['next_role_start'] = data_df.groupby('group_id')['Start Date'].shift(-1) - pd.Timedelta(days=1) data_df.loc[~data_df['is_company_header'], 'End Date'] = ( data_df['next_role_start'].fillna(data_df['company_total_end']) ) # Step6:格式还原+清理临时列 data_df['Start Date'] = data_df['Start Date'].dt.strftime('%d/%m/%Y') data_df['End Date'] = pd.to_datetime(data_df['End Date']).dt.strftime('%d/%m/%Y') result_df = data_df.drop(columns=['is_company_header', 'group_id', 'company_name', 'company_total_end', 'next_role_start']) # 输出结果 print(result_df)
注意事项
- 判断组首行时用
-(前后带空格)作为匹配规则,不会误判日期格式里的斜杠或者其他位置的短横杠,分组准确率更高。 - 所有涉及日期加减的操作必须先把列转为pandas的datetime类型,直接操作字符串会出现计算错误。
- 这种分组+窗口函数的实现方式比逐行遍历性能高很多,数据量较大时优势更明显。
内容的提问来源于stack exchange,提问作者Emily
相关产品推荐
相关产品推荐

